学习使用Go反射的用法示例

2020-01-28 14:16:59丽君

变量的类型输出如下:


Type is and kind is slice
   Contained type:
   Type is int and kind is int
 Type is string and kind is string
 Type is and kind is ptr
   Contained type:
   Type is string and kind is string
 Type is Foo and kind is struct
   Field 1 name is A type is int and kind is int
     Tag is tag1:"First Tag" tag2:"Second Tag"
     tag1 is First Tag tag2 is Second Tag
   Field 2 name is B type is string and kind is string
 Type is and kind is ptr
   Contained type:
   Type is Foo and kind is struct
     Field 1 name is A type is int and kind is int
       Tag is tag1:"First Tag" tag2:"Second Tag"
       tag1 is First Tag tag2 is Second Tag
     Field 2 name is B type is string and kind is string

Run in go playground: https://play.golang.org/p/lZ97yAUHxX

使用反射创建新实例

除了检查变量的类型外,还可以使用反射来读取,设置或创建值。首先,需要使用refVal := reflect.ValueOf(var) 为变量创建一个reflect.Value实例。如果希望能够使用反射来修改值,则必须使用refPtrVal := reflect.ValueOf(&var);获得指向变量的指针。如果不这样做,则可以使用反射来读取该值,但不能对其进行修改。

一旦有了reflect.Value实例就可以使用Type()方法获取变量的reflect.Type。

如果要修改值,请记住它必须是一个指针,并且必须首先对其进行解引用。使用refPtrVal.Elem().Set(newRefVal)来修改值,并且传递给Set()的值也必须是reflect.Value。

如果要创建一个新值,可以使用函数newPtrVal := reflect.New(varType)来实现,并传入一个reflect.Type。这将返回一个指针值,然后可以像上面那样使用Elem().Set()对其进行修改。

最后,你可以通过调用Interface()方法从reflect.Value回到普通变量值。由于Go没有泛型,因此变量的原始类型会丢失;该方法返回类型为interface{}的值。如果创建了一个指针以便可以修改该值,则需要使用Elem().Interface()解引用反射的指针。在这两种情况下,都需要将空接口转换为实际类型才能使用它。

下面的代码来演示这些概念:


type Foo struct {
  A int `tag1:"First Tag" tag2:"Second Tag"`
  B string
}

func main() {
  greeting := "hello"
  f := Foo{A: 10, B: "Salutations"}

  gVal := reflect.ValueOf(greeting)
  // not a pointer so all we can do is read it
  fmt.Println(gVal.Interface())

  gpVal := reflect.ValueOf(&greeting)
  // it's a pointer, so we can change it, and it changes the underlying variable
  gpVal.Elem().SetString("goodbye")
  fmt.Println(greeting)

  fType := reflect.TypeOf(f)
  fVal := reflect.New(fType)
  fVal.Elem().Field(0).SetInt(20)
  fVal.Elem().Field(1).SetString("Greetings")
  f2 := fVal.Elem().Interface().(Foo)
  fmt.Printf("%+v, %d, %sn", f2, f2.A, f2.B)
}

他们的输出如下:


hello
goodbye
{A:20 B:Greetings}, 20, Greetings