我們項目中反射一般是在特定場合獲取對象的信息, 然后動態調用對象方法 或者修改對象的屬性,但是go里面還有指針【地址】一說法, 來看看是怎么用的
package main import ( "fmt" "reflect" ) func main() { var x float64 = 3.4 p := reflect.ValueOf(&x) // Note: take the address of x. /*為了得到 p 指向的數據,可以調用 Value 類型的 Elem 方法。 Elem 方法能夠對指針進行“解引用”,然后將結果存儲到反射 Value 類型對象 v 中*/ v := p.Elem() v.SetFloat(7.1) fmt.Println(x) }
如果是常見的類型 struct又該如何了:
package main
import (
"fmt"
"reflect"
)
func main() {
type T struct {
A int
B string `json:"b"`
}
t := T{23, "skidoo"}
s := reflect.ValueOf(&t).Elem()
///獲取反射信息
typeOfT := s.Type()
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
fmt.Printf("%d: %s %s = %v\n", i,
typeOfT.Field(i).Name, f.Type(), f.Interface())
}
// 通過字段名, 找到字段類型信息
if bType, ok := typeOfT.FieldByName("B"); ok {
// 從tag中取出需要的tag
fmt.Printf("B has tag %s\n", bType.Tag.Get("json"))
}
//修改對象數據
s.Field(0).SetInt(77)
s.Field(1).SetString("Sunset Strip")
fmt.Println("t is now", t)
}
運行結果:
0: A int = 23
1: B string = skidoo
B has tag b
t is now {77 Sunset Strip}
如果我們修改了程序讓 s 由 t(而不是 &t)創建,程序就會在調用 SetInt 和 SetString 的地方失敗,因為 t 的字段是不可設置的。
普通方法的調用:
package main import ( "fmt" "reflect" ) // 普通函數 func add(a, b int) int { return a + b } func main() { // 將函數包裝為反射值對象 funcValue := reflect.ValueOf(add) // 構造函數參數, 傳入兩個整型值 paramList := []reflect.Value{reflect.ValueOf(10), reflect.ValueOf(20)} // 反射調用函數 retList := funcValue.Call(paramList) // 獲取第一個返回值, 取整數值 fmt.Println(retList[0].Int()) }
接口方法
package main import ( "fmt" "reflect" ) type Table interface { TableName() string } type Cal interface { Add(a, b int) int } type model struct{} func (m model) TableName() string { return "table_name" } func (m model) Add(a, b int) int { return a + b } func main() { var mod model getTableName(mod) } /* reflect.New()函數的聲明 func New(typ Type) Value 根據傳入的tpye,可以獲取到對應的value */ func getTableName(v interface{}) { rt := reflect.TypeOf(v) rv := reflect.ValueOf(v) if tabler, ok := rv.Interface().(Table); ok { fmt.Println(tabler.TableName()) } if cal, ok := rv.Interface().(Cal); ok { fmt.Println(cal.Add(10, 20)) } /// if tabler, ok := reflect.New(rt).Interface().(Table); ok { fmt.Println(tabler.TableName()) } if cal, ok := reflect.New(rt).Interface().(Cal); ok { fmt.Println(cal.Add(20, 30)) } }
對象方法:
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int
Sex string
}
//如果Tool小寫后面就沒辦法反射
type Tool struct {
Cap string
Key string
}
func (t Tool) Print() {
fmt.Println("tool:" + t.Cap + t.Key)
}
func (p Person) PrintInfo(t *Tool) {
t.Cap = "green"
t.Key = "long"
fmt.Printf("姓名:%s, 年齡:%s, 性別:%s, 參數tool內容:%s %s\n", p.Name, p.Age, p.Sex, t.Key, t.Cap)
}
func main() {
p1 := Person{"Rbuy", 20, "男"}
///調用person的PrintInfo 方法
rtyp := reflect.TypeOf(p1)
rcvr := reflect.ValueOf(p1)
rmethod, ok := rtyp.MethodByName("PrintInfo")
if ok {
// 得到第一個此method第1參數的Type,第零個當然就是結構體本身了
replyType := rmethod.Type.In(1).Elem()
//實例化返回值的地址 *tool
replyv := reflect.New(replyType)
//rcvr 可以理解為對象實例 replyv 理解為返回值
rmethod.Func.Call([]reflect.Value{rcvr, replyv})
//調用tool的print
var t Tool
rtyp = reflect.TypeOf(t)
rmethod, ok = rtyp.MethodByName("Print")
if ok {
rmethod.Func.Call([]reflect.Value{replyv.Elem()})
}
}
}