gpt4 book ai didi

string - 如何将字符串值转换为正确的 reflect.Kind?

转载 作者:IT王子 更新时间:2023-10-29 01:20:10 26 4
gpt4 key购买 nike

Go 中是否有一个通用的辅助方法来根据reflect.Kindstring 转换为正确的值?

还是需要自己实现各种切换?

我有一个类似于“143”的字符串值和一个类型为“UInt16”的 reflect.Value,我想转换该字符串值并将其设置为我的结构的 UInt16 值。

我当前的代码如下:

func setValueFromString(v reflect.Value, strVal string) error {
switch v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
val, err := strconv.ParseInt(strVal, 0, 64)
if err != nil {
return err
}
if v.OverflowInt(val) {
return errors.New("Int value too big: " + strVal)
}
v.SetInt(val)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
val, err := strconv.ParseUint(strVal, 0, 64)
if err != nil {
return err
}
if v.OverflowUint(val) {
return errors.New("UInt value too big: " + strVal)
}
v.SetUint(val)
case reflect.Float32:
val, err := strconv.ParseFloat(strVal, 32)
if err != nil {
return err
}
v.SetFloat(val)
case reflect.Float64:
val, err := strconv.ParseFloat(strVal, 64)
if err != nil {
return err
}
v.SetFloat(val)
case reflect.String:
v.SetString(strVal)
case reflect.Bool:
val, err := strconv.ParseBool(strVal)
if err != nil {
return err
}
v.SetBool(val)
default:
return errors.New("Unsupported kind: " + v.Kind().String())
}
return nil
}

这已经有效了,但我想知道是否已经在其他地方实现了。

最佳答案

编辑:原始问题(“如何从 string 表示中获取 reflect.Kind”)的答案是在最后。对您编辑的问题的回答如下:


您正在做的是最快和“最安全”的。如果你不想麻烦那个大的 switch,你可以利用例如json已包含此 开关 的包以从 JSON 字符串解码值(在 encoding/json/decode.go 中,未导出的函数 literalStore())。

您的解码函数可能如下所示:

func Set(v interface{}, s string) error {
return json.Unmarshal([]byte(s), v)
}

json.Unmarshal() 的简单调用.使用/测试它:

{
var v int
err := Set(&v, "1")
fmt.Println(v, err)
}
{
var v int
err := Set(&v, "d")
fmt.Println(v, err)
}
{
var v uint32
err := Set(&v, "3")
fmt.Println(v, err)
}
{
var v bool
err := Set(&v, "true")
fmt.Println(v, err)
}
{
var v float32
err := Set(&v, `5.1`)
fmt.Println(v, err)
}
{
var v string
err := Set(&v, strconv.Quote("abc"))
fmt.Println(v, err)
}

需要注意的一件事:当你想传递一个string时,它必须被引用,例如与 strconv.Quote() .输出(在 Go Playground 上尝试):

1 <nil>
0 invalid character 'd' looking for beginning of value
3 <nil>
true <nil>
5.1 <nil>
abc <nil>

如果您不想使用带引号的字符串(这只会使事情复杂化),您可以将其构建到 Set() 函数中:

func Set(v interface{}, s string) error {
if t := reflect.TypeOf(v); t.Kind() == reflect.Ptr &&
t.Elem().Kind() == reflect.String {
s = strconv.Quote(s)
}
return json.Unmarshal([]byte(s), v)
}

然后您可以使用 string 变量的地址和未加引号的 string 值来调用它:

var v string
err := Set(&v, "abc")
fmt.Println(v, err)

Go Playground 上尝试这个变体.


原始问题的答案:如何从其 string 表示中获取 reflect.Kind:

声明reflect.Kind :

type Kind uint

reflect.Kind 的不同值是常量:

const (
Invalid Kind = iota
Bool
Int
Int8
// ...
Struct
UnsafePointer
)

还有 reflect包只为 reflect.Kind() 类型提供一个方法:

func (k Kind) String() string

因此,就目前而言,您无法从其 string 表示中获得 reflect.Kind(使用 Kind.String() 方法只能进行相反的方向)。但提供此功能并不难。

我们要做的是从所有种类构建一个 map :

var strKindMap = map[string]reflect.Kind{}

我们这样初始化它:

func init() {
for k := reflect.Invalid; k <= reflect.UnsafePointer; k++ {
strKindMap[k.String()] = k
}
}

这是可能且正确的,因为常量是使用 iota 初始化的其计算结果为连续的无类型整数常量,第一个值为 reflect.Invalid,最后一个值为 reflect.UnsafePointer

现在您可以通过简单地对该 map 进行索引,从其 string 表示中获取 reflect.Kind。执行此操作的辅助函数:

func strToKind(s string) reflect.Kind {
k, ok := strKindMap[s]
if !ok {
return reflect.Invalid
}
return k
}

我们完成了。测试/使用它:

fmt.Printf("All: %#v\n", strKindMap)

for _, v := range []string{"Hey", "uint8", "ptr", "func", "chan", "interface"} {
fmt.Printf("String: %q, Kind: %v (%#v)\n", v, strToKind(v), strToKind(v))
}

输出(在 Go Playground 上尝试):

All: map[string]reflect.Kind{"int64":0x6, "uint8":0x8, "uint64":0xb, "slice":0x17, "uintptr":0xc, "int8":0x3, "array":0x11, "interface":0x14, "unsafe.Pointer":0x1a, "complex64":0xf, "complex128":0x10, "int":0x2, "uint":0x7, "int16":0x4, "uint16":0x9, "map":0x15, "bool":0x1, "int32":0x5, "ptr":0x16, "string":0x18, "func":0x13, "struct":0x19, "invalid":0x0, "uint32":0xa, "float32":0xd, "float64":0xe, "chan":0x12}
String: "Hey", Kind: invalid (0x0)
String: "uint8", Kind: uint8 (0x8)
String: "ptr", Kind: ptr (0x16)
String: "func", Kind: func (0x13)
String: "chan", Kind: chan (0x12)
String: "interface", Kind: interface (0x14)

关于string - 如何将字符串值转换为正确的 reflect.Kind?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39891689/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com