【问题标题】:How to set tags while using reflect.New使用reflect.New时如何设置标签
【发布时间】:2020-02-17 10:25:33
【问题描述】:

从现有结构创建新结构时,不会在新结构上设置标签。

例如:

package main

import (
    "fmt"
    "reflect"
)

type Foo struct {
  Bar string `custom:"tag"`
}

func readTag(e interface{}) {
  t := reflect.TypeOf(e).Elem()
  f, _ := t.FieldByName("Bar")
  fmt.Println(f.Tag)
}

func main() {
  foo := &Foo{"baz"}

  fmt.Println(foo)
  readTag(foo)

  fooType := reflect.TypeOf(foo).Elem()
  newFoo := reflect.New(fooType).Elem()
  newFoo.FieldByName("Bar").SetString("baz2")
  fmt.Println(newFoo)
  readTag(&newFoo)// empty
}

游乐场链接:https://play.golang.org/p/7-zMPnwQ8Vo

使用reflect.New时如何设置标签?甚至可能吗?

【问题讨论】:

    标签: pointers go struct go-reflect


    【解决方案1】:

    标签不属于实例,标签属于类型。

    因此,当您创建类型的新实例时,它们的类型将是相同的“佩戴”相同的标签。使用文字或通过 reflect 包创建新实例都没有关系。

    您的问题是newFooreflect.Value 类型,而&newFoo*reflect.Value 类型,它不是指向您的结构的指针(不是*Foo 类型)。

    如果你解开结构体值:

    newFoo.Interface()
    

    然后你传递这个,你使Elem() 调用可选(只有当它是一个指针时才这样做):

    func readTag(e interface{}) {
        t := reflect.TypeOf(e)
        if t.Kind() == reflect.Ptr {
            t = t.Elem()
        }
        f, _ := t.FieldByName("Bar")
        fmt.Println(f.Tag)
    }
    

    然后你会得到相同的标签(在Go Playground上试试):

    &{baz}
    custom:"tag"
    {baz2}
    custom:"tag"
    

    如果你保持 reflect.Value 包裹结构指针并从中解开,你会得到相同的结果:

    newFooPtr := reflect.New(fooType)
    newFoo := newFooPtr.Elem()
    newFoo.FieldByName("Bar").SetString("baz2")
    fmt.Println(newFoo)
    readTag(newFooPtr.Interface()) // empty
    

    那么readTag()就不需要修改了。在Go Playground 上试试这个版本。

    【讨论】:

    • 很好的答案。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多