我有一个结构人员.
type Person struct {
Firstname string
Lastname string
Years uint8
}
Run Code Online (Sandbox Code Playgroud)
然后我有这个结构的两个实例,PersonA和PersonB.
PersonA := {"", "Obama", 6}
PersonB := {"President", "Carter", 8}
Run Code Online (Sandbox Code Playgroud)
我想编写一个函数,在给定每个字段的某些条件(即非空)的情况下,将值从PersonA复制到PersonB.我知道如何通过对字段名称进行硬编码来实现这一点,但是我想要一个即使我更改Person结构也能工作的函数.
我知道Go反射是有帮助的,但问题是获取并设置值需要知道类型,如果你想使用像SetInt这样的东西.但有一种"简单"的方法吗?
**Javascript类比**在Javascript中,你可以做一个(在someObject中的属性)循环.
(for propt in personA) {
if personA[propt] != "" {
// do something
personB[propt] = personA[propt]
}
}
Run Code Online (Sandbox Code Playgroud)
我已经排除的选项:
跟踪地图中每个结构中的字段,然后使用反射pkg中的FieldByName和Set*函数集合的组合.
手动创建一个循环遍历Person(下面).因为我想为许多其他结构(学校,动物等)做这种类型的"更新"
if PersonA.Firstname != "" {
PersonB.Firstname = PersonA.Firstname
}
Run Code Online (Sandbox Code Playgroud)
...
if PersonA.Years != "" {
PersonB.Years = PersonA.Years
}
Run Code Online (Sandbox Code Playgroud)下面的问题让我在那里中途,但仍然不能扩展到我想要利用这个"更新"功能的所有结构.
在Golang中,使用reflect,如何设置struct字段的值?
**其他有用的链接** GoLang:按名称访问struct属性
使用reflect.ValueOf()转换为具体类型.之后,您可以使用reflect.Value.SetString来设置所需的值.
structValue := FooBar{Foo: "foo", Bar: 10}
fields := reflect.TypeOf(structValue)
values := reflect.ValueOf(structValue)
num := fields.NumField()
for i := 0; i < num; i++ {
field := fields.Field(i)
value := values.Field(i)
fmt.Print("Type:", field.Type, ",", field.Name, "=", value, "\n")
switch value.Kind() {
case reflect.String:
v := value.String()
fmt.Print(v, "\n")
case reflect.Int:
v := strconv.FormatInt(value.Int(), 10)
fmt.Print(v, "\n")
case reflect.Int32:
v := strconv.FormatInt(value.Int(), 10)
fmt.Print(v, "\n")
case reflect.Int64:
v := strconv.FormatInt(value.Int(), 10)
fmt.Print(v, "\n")
default:
assert.Fail(t, "Not support type of struct")
}
}
Run Code Online (Sandbox Code Playgroud)
这是解决方案f2.Set(reflect.Value(f))的关键
package main
import (
"fmt"
"reflect"
)
func main() {
type T struct {
A int
B string
}
t := T{23, "skidoo"}
t2:= T{}
s := reflect.ValueOf(&t).Elem()
s2 := reflect.ValueOf(&t2).Elem()
typeOfT := s.Type()
fmt.Println("t=",t)
fmt.Println("t2=",t2)
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
f2:= s2.Field(i)
fmt.Printf("%d: %s %s = %v\n", i,
typeOfT.Field(i).Name, f.Type(), f.Interface())
fmt.Printf("%d: %s %s = %v\n", i,
typeOfT.Field(i).Name, f2.Type(), f2.Interface())
f2.Set(reflect.Value(f))
fmt.Printf("%d: %s %s = %v\n", i,
typeOfT.Field(i).Name, f2.Type(), f2.Interface())
}
fmt.Println("t=",t)
fmt.Println("t2=",t2)
}
Output:
t= {23 skidoo}
t2= {0 }
0: A int = 23
0: A int = 0
0: A int = 23
1: B string = skidoo
1: B string =
1: B string = skidoo
t= {23 skidoo}
t2= {23 skidoo}
Run Code Online (Sandbox Code Playgroud)
http://play.golang.org/p/UKFMBxfbZD
反思应该是你所需要的。这看起来与“深度复制”语义相似(尽管不完全相同),该语义已在https://godoc.org/github.com/getlantern/deepcopy上实现
您应该能够根据您的需求进行调整,或者至少从中汲取一些想法。