为了账号安全,请及时绑定邮箱和手机立即绑定

如何根据结构字段类型对值进行类型转换?

如何根据结构字段类型对值进行类型转换?

Go
九州编程 2022-06-21 10:44:09
我正在尝试创建一个填充给定字段的方法struct,但是要设置正确的值,我需要转换值以检查类型是否与结构字段类型匹配。例子:type S struct {    Name string    Age int}该值将始终是string因为它来自 URL。const stubQuery = "name=sam&page=30"query, _ := url.ParseQuery(stubQuery)// e.g result: {"name": ["sam"], "age": ["30"]}我已经设法迭代query并从S结构中获取字段,但是我怎样才能获取字段类型并将“30”转换为结构类型?structValue := reflect.ValueOf(&S{}).Elem()structFieldValue := structValue.FieldByName("Age")structFieldType := structFieldValue.Type()val := reflect.ValueOf("30")if structFieldType != val.Type() {} // Always false
查看完整描述

2 回答

?
UYOU

TA贡献1878条经验 获得超4个赞

应用程序必须将字符串解析为可分配给该字段的值。


使用类型开关和值开关查找要解析的类型或种类。


使用strconv 包解析数值和布尔值。使用time 包来解析时间和持续时间。


这是一些示例代码:


v := reflect.ValueOf(&s).Elem()

t := v.Type()

for i := 0; i < t.NumField(); i++ {

    sf := t.Field(i)


    // Get value from query. Skip if not set.

    values, ok := query[strings.ToLower(sf.Name)]

    if !ok || len(values) == 0 {

        continue

    }


    // Use type switch for specific types.

    switch f := v.Field(i).Addr().Interface().(type) {


    case *time.Time:

        var err error

        *f, err = time.Parse(time.RFC3339, values[0])

        if err != nil {

            log.Fatal(err)

        }

    case *time.Duration:

        var err error

        *f, err = time.ParseDuration(values[0])

        if err != nil {

            log.Fatal(err)

        }


    default:

        // The specific type was not handled. Fallback

        // to using the field kind. This allows us to

        // handle all numeric and bool types without knowing

        // those types explicitly.


        switch sf.Type.Kind() {

        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:

            n, err := strconv.ParseInt(values[0], 10, sf.Type.Bits())

            if err != nil {

                log.Fatal(err)

            }

            v.Field(i).SetInt(n)

        case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:

            n, err := strconv.ParseUint(values[0], 10, sf.Type.Bits())

            if err != nil {

                log.Fatal(err)

            }

            v.Field(i).SetUint(n)

        case reflect.Float64, reflect.Float32:

            n, err := strconv.ParseFloat(values[0], sf.Type.Bits())

            if err != nil {

                log.Fatal(err)

            }

            v.Field(i).SetFloat(n)

        case reflect.Bool:

            b, err := strconv.ParseBool(values[0])

            if err != nil {

                log.Fatal(err)

            }

            v.Field(i).SetBool(b)

        case reflect.String:

            v.Field(i).SetString(values[0])

        default:

            log.Fatal("unknown type")

        }

    }

}

首先检查类型,以便将 time.Duration 解析为持续时间而不是整数。


将 log.Fatal 调用替换为适合您的场景的错误处理。


查看完整回答
反对 回复 2022-06-21
?
牧羊人nacy

TA贡献1862条经验 获得超7个赞

val := reflect.ValueOf("30")

传入参数的类型("30"在您的示例代码中)是string。它的类型永远不会匹配数字字段的类型。


你必须检查structFieldType,以确定你应该应用什么转换val。


另一种方法可能是向您的结构添加一个特定的方法来填充它的字段:


AssignFields(in url.Values) error

# or

AssignField(name string, value string) error


查看完整回答
反对 回复 2022-06-21
  • 2 回答
  • 0 关注
  • 126 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信