在 Golang 结构字段中保存类型
Hold a type in a Golang struct field
我正在寻找一种方法来将类型(可能 reflection.Type?)作为自定义结构中的字段。这背后的原因是我正在将 JSON 数组解码为结构,我稍后会从中构建 SQL 查询,但是 JSON 数组中的整数、浮点数和时间戳是相同的,尽管它们是查询数据库时不同。这意味着我需要在查询之前将每个值转换为正确的类型。
我认为答案在 reflect 包的某个地方,但我还没有弄清楚如何使用它。
我希望的是这样的:
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")
有什么想法吗?
我想你走在正确的轨道上。在您的 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
}
因为你说 "but ints, floats and timestamps are identical in the JSON array" 我假设你 json 中的所有值在技术上都是字符串(意味着它们都被引用)。您可能不需要所有这些字段,但想法是将类型信息与属性名称和原始值相结合。如果你使用类型 interface{}
的字段,你可以给它赋值任何东西,这样你就可以保存原始的 json 数据(名称和值)以及类型信息和合理的 Go 类型中的值这个结构的一个实例很容易。
我尝试使用@evanmcdonnal 提供的解决方案,但我找不到转换 float64
的通用方法(这是 json.Unmarshal
赋予它从 json array) 到 DB 中找到的任何数据类型(timestamp
被证明有点棘手,因为 reflect.Value
不会导出转换方法到 time.Time
,这相当于卡桑德拉的 timestamp
).
所做的工作是使用 typeConversion
字段而不是 dataType
字段,也就是说,持有一个函数,该函数从类型 json.Unmarshal
设置转换为区分列的类型变量类型为.
因此,我的结构如下所示:
type Column struct {
name string
typeConversion func(reflect.Value) reflect.Value
}
我已经拥有的一些类型转换函数如下所示:
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 ,并且因为 return 值始终是 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()
StructTag 应该有帮助:
type Table struct {
age int `sql:"type:int;`
price float `sql:"type:float;`
}
我正在寻找一种方法来将类型(可能 reflection.Type?)作为自定义结构中的字段。这背后的原因是我正在将 JSON 数组解码为结构,我稍后会从中构建 SQL 查询,但是 JSON 数组中的整数、浮点数和时间戳是相同的,尽管它们是查询数据库时不同。这意味着我需要在查询之前将每个值转换为正确的类型。
我认为答案在 reflect 包的某个地方,但我还没有弄清楚如何使用它。
我希望的是这样的:
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")
有什么想法吗?
我想你走在正确的轨道上。在您的 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
}
因为你说 "but ints, floats and timestamps are identical in the JSON array" 我假设你 json 中的所有值在技术上都是字符串(意味着它们都被引用)。您可能不需要所有这些字段,但想法是将类型信息与属性名称和原始值相结合。如果你使用类型 interface{}
的字段,你可以给它赋值任何东西,这样你就可以保存原始的 json 数据(名称和值)以及类型信息和合理的 Go 类型中的值这个结构的一个实例很容易。
我尝试使用@evanmcdonnal 提供的解决方案,但我找不到转换 float64
的通用方法(这是 json.Unmarshal
赋予它从 json array) 到 DB 中找到的任何数据类型(timestamp
被证明有点棘手,因为 reflect.Value
不会导出转换方法到 time.Time
,这相当于卡桑德拉的 timestamp
).
所做的工作是使用 typeConversion
字段而不是 dataType
字段,也就是说,持有一个函数,该函数从类型 json.Unmarshal
设置转换为区分列的类型变量类型为.
因此,我的结构如下所示:
type Column struct {
name string
typeConversion func(reflect.Value) reflect.Value
}
我已经拥有的一些类型转换函数如下所示:
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 ,并且因为 return 值始终是 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()
StructTag 应该有帮助:
type Table struct {
age int `sql:"type:int;`
price float `sql:"type:float;`
}