原始类型

让我们来看看可以对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)

最后更新于