原始类型

让我们来看看可以对int或string这种原始类型做什么操作。

获取类型

package main
import (
"fmt"
"reflect"
)
func printType(v interface{}) {
rv := reflect.ValueOf(v)
typ := rv.Type()
typeName := ""
switch rv.Kind() {
case reflect.Ptr:
typeName = "pointer"
case reflect.Int:
typeName = "int"
case reflect.Int32:
typeName = "int32"
case reflect.String:
typeName = "string"
// ... handle more cases
default:
typeName = "unrecognized type"
}
fmt.Printf("v is of type '%s'. Size: %d bytes\n", typeName, typ.Size())
}
func main() {
printType(int32(3))
printType("")
i := 3
printType(&i) // *int i.e. pointer to int
}
/*
---------OUTPUT---------
v is of type 'int32'. Size: 4 bytes
v is of type 'string'. Size: 16 bytes
v is of type 'pointer'. Size: 8 bytes
*/
在实际代码中,你可以处理你关心的所有类型

获取值

package main
import (
"fmt"
"reflect"
)
func getIntValue(v interface{}) {
var reflectValue = reflect.ValueOf(v)
n := reflectValue.Int()
fmt.Printf("Int value is: %d\n", n)
}
func main() {
getIntValue(3)
getIntValue(int8(4))
getIntValue("")
}
/*
Int value is: 3
Int value is: 4
panic: reflect: call of reflect.Value.Int on string Value
goroutine 1 [running]:
reflect.Value.Int(0x111f900, 0x1162920, 0x98, 0x0)
/usr/local/go/src/reflect/value.go:986 +0x1a9
main.getIntValue(0x111f900, 0x1162920)
/Users/ju/gowork/src/test/main.go:24 +0x7e
main.main()
/Users/ju/gowork/src/test/main.go:31 +0x7b
Exiting.
*/
为了最小化API的表示,Int()返回int64可处理所有有符号整型值(int8, int16, int32, int64)。
UInt()方法返回uint64,可处理每种有符号整型值(uint8, uint16, uint32, uint64)。
试图从不兼容类型的值(如字符串)获取整型值,将会引发恐慌。
为了避免恐慌,您可以先用Kind()方法检查值的类型。
获取值的所有方法:
  • Bool() bool
  • Int() int64
  • UInt() uint64
  • Float() float64
  • String() string
  • Bytes() []byte

设置值

package main
import (
"fmt"
"reflect"
)
type S struct {
N int
}
func setIntPtr() {
var n int = 2
reflect.ValueOf(&n).Elem().SetInt(4)
fmt.Printf("setIntPtr: n=%d\n", n)
}
func setStructFieldDirect() {
var s S
reflect.ValueOf(&s.N).Elem().SetInt(5)
fmt.Printf("setStructFieldDirect: n=%d\n", s.N)
}
func setStructPtrField() {
var s S
reflect.ValueOf(&s).Elem().Field(0).SetInt(6)
fmt.Printf("setStructPtrField: s.N: %d\n", s.N)
}
func handlePanic(funcName string) {
if msg := recover(); msg != nil {
fmt.Printf("%s panicked with '%s'\n", funcName, msg)
}
}
func setStructField() {
defer handlePanic("setStructField")
var s S
reflect.ValueOf(s).Elem().Field(0).SetInt(4)
fmt.Printf("s.N: %d\n", s.N)
}
func setInt() {
defer handlePanic("setInt")
var n int = 2
rv := reflect.ValueOf(n)
rv.Elem().SetInt(4)
}
func setIntPtrWithString() {
defer handlePanic("setIntPtrWithString")
var n int = 2
reflect.ValueOf(&n).Elem().SetString("8")
}
func main() {
setIntPtr()
setStructFieldDirect()
setStructPtrField()
setInt()
setStructField()
setIntPtrWithString()
}
/*
---------OUTPUT-----------
setIntPtr: n=4
setStructFieldDirect: n=5
setStructPtrField: s.N: 6
setInt panicked with 'reflect: call of reflect.Value.Elem on int Value'
setStructField panicked with 'reflect: call of reflect.Value.Elem on struct Value'
setIntPtrWithString panicked with 'reflect: call of reflect.Value.SetString on int Value'
*/
setIntsetStructField展示的那样,只有拿到指向值的指针时,才可以修改值。
因为reflect.ValueOf()创建了一个reflect.Value 变量,它是一个指向值的指针变量,所以你需要用Elem()来获取reflect.Value所表示的值本身,然后再调用SetInt() 为它设置值。
setStructPtrField展示了如何通过字段在结构体中的位置来取得字段值的引用。
试图设置类型不兼容的值会导致恐慌。
设置值的方法跟读取值的方法是镜像存在的:
  • SetBool(v bool)
  • SetInt(v int64)
  • SetUInt(v uint64)
  • SetFloat(v float64)
  • SetString(v string)
  • SetBytes(v []byte)