Reputation: 564
When creating a new struct from existing struct, tags are not set on the new struct.
For example:
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
}
Playground link: https://play.golang.org/p/7-zMPnwQ8Vo
How to set tags while using reflect.New
? Is it even possible?
Upvotes: 1
Views: 2007
Reputation: 418247
Tags do not belong to instances, tags belong to types.
So when you create new instances of your type, their type will be the same "wearing" the same tags. It doesn't matter if you create new instances with literals or via the reflect
package.
The problem in your case is that newFoo
is of type reflect.Value
, and &newFoo
is of type *reflect.Value
, it's not a pointer to your struct (not of type *Foo
).
If you unwrap the struct value:
newFoo.Interface()
And you pass this, and you make the Elem()
call optional (only do it if it's a pointer):
func readTag(e interface{}) {
t := reflect.TypeOf(e)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
f, _ := t.FieldByName("Bar")
fmt.Println(f.Tag)
}
Then you'll get the same tag (try it on the Go Playground):
&{baz}
custom:"tag"
{baz2}
custom:"tag"
You get the same result if you keep the reflect.Value
wrapping the struct pointer, and unwrap from it:
newFooPtr := reflect.New(fooType)
newFoo := newFooPtr.Elem()
newFoo.FieldByName("Bar").SetString("baz2")
fmt.Println(newFoo)
readTag(newFooPtr.Interface()) // empty
Then readTag()
doesn't need to be modified. Try this version on the Go Playground.
Upvotes: 4