【问题标题】:Hold a type in a Golang struct field在 Golang 结构字段中保存一个类型
【发布时间】:2016-09-28 00:06:00
【问题描述】:

我正在寻找一种方法来将类型(可能是反射。类型?)作为自定义结构中的字段。这背后的原因是我将 JSON 数组解码为结构,稍后我会从中构建 SQL 查询,但是 JSON 数组中的整数、浮点数和时间戳是相同的,尽管在查询数据库时它们是不同的。这意味着我需要在查询之前将每个值转换为正确的类型。

我认为答案就在反射包的某个地方,但我还没有弄清楚如何使用它。

我希望是这样的:

type Column struct {
    name string
    dataType type
}
someColumn := Column {name: "somecol", dataType: int}
convertedVal := SomeConversionFunc("5", someColumn.dataType)

或者,这种事情也可以工作:

type Column struct {
    name string
    dataType func()
}
someColumn := Column {name: "somecol", dataType: ConvertToInt}
convertedVal := someColumn.dataType("5")

有什么想法吗?

【问题讨论】:

  • 看来你需要一个 ORM 包。
  • 我不确定这是否是解决方案。一切都被解码为字符串,这意味着我需要将这些字符串转换为相应列的数据类型,然后再将它们传递给查询构建器(我正在使用 squirrel 创建 Cassandra 查询 - CQL)

标签: reflection struct go


【解决方案1】:

我想你是在正确的轨道上。在您的Column 结构中,您正在寻找reflect.Type。您将通过import "reflect" 获得。

如果您的列结构包含类型名称和值(作为原始字符串),您应该能够编写打开类型并为每种情况生成正确类型的值的方法。此处开关的简要参考; https://golang.org/doc/effective_go.html#switch

type Column struct {
    Name string
    DataType reflect.Type
    TypedValue interface{}
    StringValue string
}

因为您说“但 JSON 数组中的整数、浮点数和时间戳是相同的”,所以我假设您的 json 中的所有值在技术上都是字符串(意味着它们都被引用了)。您可能不需要所有这些字段,但想法是将类型信息与属性名称和原始值相结合。如果您使用interface{} 类型的字段,您可以为其分配任何内容,以便您可以在此结构的实例中保存原始 json 数据(名称和值)以及类型信息和合理 Go 类型中的值。很容易。

【讨论】:

  • 对不起,我不太明白。 dataType 字段应该是字符串还是 reflect.Type?如果是reflect.Type,那么我如何输入一个int类型,例如?如果是字符串,是否有一个函数可以使用字符串进行转换以表示所需的类型?
  • @SivanBH dataType 应该是 reflect.Type。对于任何实例i(任何类型),您都可以使用reflect.TypeOf 获取它的类型。我将使用我认为更合理的模型样本进行编辑。我将导出所有字段,您可以根据需要进行更改。
  • 据我所知,这也是如此,但它似乎不起作用。例如,如果 DataType 应该是 int,我使用 reflect.Int,但这实际上不是 reflect.Type,而是 reflect.Kind。而且无论哪种方式,reflect提供的转换方法都只能作为reflect.Value实现的方法。我在这里错过了什么?
【解决方案2】:

我尝试使用@evanmcdonnal 提供的解决方案,但我找不到将float64json.Unmarshal 赋予它从 json 数组解组的任何数字的类型)转换为找到的任何数据类型的通用方法在数据库中(timestamp 被证明有点棘手,因为reflect.Value 不会将转换方法导出到time.Time,这相当于Cassandra 的timestamp)。

起作用的是使用typeConversion 字段而不是dataType 字段,也就是说,持有一个从json.Unmarshal 类型转换为指定列类型的函数,将变量的类型设置为。

因此,我的结构如下所示:

type Column struct {
    name string
    typeConversion func(reflect.Value) reflect.Value
}

我已经拥有的一些 typeConversion 函数如下所示:

func floatToTime(varFloat reflect.Value) reflect.Value {
    timestamp := time.Unix(int64(varFloat.Float()), 0)
    return reflect.ValueOf(timestamp)
}

func floatToInt(varFloat reflect.Value) reflect.Value {
    return reflect.ValueOf(int(varFloat.Float()))
}

这实际上是一个很好的解决方案,因为它非常通用:结构定义了任何转换函数的构建方式,这意味着我可以包装任何形式的转换以适应这个 API,并且因为返回值始终是reflect.Value,我可以通过调用Interface() 访问具有正确类型的底层值,如下所示:

// value is the data unmarshaled by json
// I convert it to reflect.Value, then convert it again using my custom typeConversion
// Then  I use Interface() to get the final value in the final (and column-appropriate) type
column.typeConversion(reflect.ValueOf(value)).Interface()

【讨论】:

  • 这让我走上了正轨。我有一个 reflect.Type 类型的结构成员,并将其赋值为 reflect.TypeOf(variable)。
【解决方案3】:

StructTag 应该有帮助:

type Table struct {
    age int `sql:"type:int;`
    price float `sql:"type:float;`
}

【讨论】:

  • 这是一个有趣的解决方案,我还没有遇到过。但它不适合我的需求,因为我使用地图来表示用户请求的列到值。
猜你喜欢
  • 1970-01-01
  • 2017-10-07
  • 1970-01-01
  • 1970-01-01
  • 2014-09-03
  • 2013-10-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多