Go 語言進階—— 反射

項目中有多處用到反射,本文簡單列舉go中提供反射的常用case。

go reflect反射包,通過 Type和Value 分別表示反射獲取的類型和值。通過函數,reflect.TypeOf 和 reflect.ValueOf,返回被檢查對象的類型和值。例如,x 被定義爲:var x float64 = 3.4,那麼 reflect.TypeOf(x) 返回 float64,reflect.ValueOf(x) 返回 3.4

通過反射獲取變量信息

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var x float64 = 3.4
	fmt.Println("type:", reflect.TypeOf(x))
	v := reflect.ValueOf(x)
	fmt.Println("value:", v)
	fmt.Println("type:", v.Type())
	fmt.Println("kind:", v.Kind())
	fmt.Println("value:", v.Float())
	fmt.Println(v.Interface())
	fmt.Printf("value is %5.2e\n", v.Interface())
	y := v.Interface().(float64)
	fmt.Println(y)
}

輸出:

type: float64
value: 3.4
type: float64
kind: float64
value: 3.4
3.4
value is 3.40e+00
3.4

注:x 是一個 float64 類型的值,reflect.ValueOf(x).Float() 返回這個 float64 類型的實際值;同樣的適用於 Int(), Bool(), Complex(), String()

通過反射修改值

import (
	"fmt"
	"reflect"
)

func main() {
	var x float64 = 3.4
	v := reflect.ValueOf(x)
	// setting a value:
	// v.SetFloat(3.1415) // Error: will panic: reflect.Value.SetFloat using unaddressable value 原因是 v 不是可設置的
	fmt.Println("settability of v:", v.CanSet()) //可以使用 CanSet() 方法測試是否可設置
	v = reflect.ValueOf(&x) // Note: take the address of x.
	fmt.Println("type of v:", v.Type())
	fmt.Println("settability of v:", v.CanSet())

//要想讓其可設置我們需要使用 Elem() 函數,這間接的使用指針:v = v.Elem()
	v = v.Elem()
	fmt.Println("The Elem of v is: ", v)
	fmt.Println("settability of v:", v.CanSet())
	v.SetFloat(3.1415) // this works!
	fmt.Println(v.Interface())
	fmt.Println(v)
}
輸出:

settability of v: false
type of v: *float64
settability of v: false
The Elem of v is:  <float64 Value>
settability of v: true
3.1415
<float64 Value>

反射中有些內容是需要用地址去改變它的狀態值等信息。

反射結構體

package main

import (
	"fmt"
	"reflect"
)

type NotknownType struct {
	s1, s2, s3 string
}

func (n NotknownType) String() string {
	return n.s1 + " - " + n.s2 + " - " + n.s3
}

// variable to investigate:
var secret interface{} = NotknownType{"Ada", "Go", "Oberon"}

func main() {
	value := reflect.ValueOf(secret) // <main.NotknownType Value>
	typ := reflect.TypeOf(secret)    // main.NotknownType
	//typ := value.Type()  // main.NotknownType
	fmt.Println(typ)
	knd := value.Kind() // struct
	fmt.Println(knd)

	// iterate through the fields of the struct: value.NumField()反射遍歷結構體屬性
	for i := 0; i < value.NumField(); i++ {
        //value.Field獲取值
		fmt.Printf("Field %d: %v\n", i, value.Field(i))


		// error: panic: reflect.Value.SetString using value obtained using unexported field
        //結構中只有被導出字段(首字母大寫)纔是可設置的
		//value.Field(i).SetString("C#")
	}

	// call the first method, which is String():
	results := value.Method(0).Call(nil)
	fmt.Println(results) // [Ada - Go - Oberon]
}
輸出:

main.NotknownType
struct
Field 0: Ada
Field 1: Go
Field 2: Oberon
[Ada - Go - Oberon]

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章