[Golang] Reflect


STORY

Golang中有一種型態為interface{}, 主要就是像動態語言,
可以賦予它任何型態的值, 如struct, map, slice等...
但當你在使用時, 就需要Reflect來辨認它的型態.

DESCRIPTION

將一個指向Struct的pointer丟到interface中,
此時可以看見他回傳的是一個指向Struct的pointer的Type:

type Struct struct {
    Name string
}

func main()  {
    str := &Struct{
        Name: "Struct",
    }
    var inter interface{} = str
    sType := reflect.TypeOf(inter)
    fmt.Println(sType) // *main.Struct
}




若今日我有個需求是, 我需要根據interface中的pointer型態,
去建立一個該型態的物件 (非pointer),
那麼可以使用以下方法:

type Struct struct {
    Name string
}

func main()  {
    str := &Struct{
        Name: "Struct",
    }
// ******** part 1 ********
    var inter interface{} = str
    sType := reflect.TypeOf(inter)
    fmt.Println(sType) // *main.Struct

// ******** part 2 ********
    sValue := reflect.New(sType.Elem())
    fmt.Println(reflect.TypeOf(sValue.Elem().Interface()))  // main.Struct
}

可在part 2發現有個.Elem()的方法, 它有點像在C語言中的取址符&,
但比較特別的是它也可以用在slice身上,
上述就是取Pointer指向的Struct,
並且把它New出來, 而與C相同New出來的type,
一樣會返回一個指向該空間的pointer給你,
所以在最後把它轉為interface的時候,
需要再做一次Elem()的動作.


最後若我們需要針對該型態來建立一個slice該怎麼做呢?
可以參考以下程式碼:

type Struct struct {
    Name string
}

func main()  {
    str := &Struct{
        Name: "Struct",
    }
// ******** part 1 ********
    var inter interface{} = str
    sType := reflect.TypeOf(inter)
    fmt.Println(sType) // *main.Struct

// ******** part 2 ********
    sValue := reflect.New(sType.Elem())
    sSliceType := reflect.SliceOf(sType.Elem())
    sSliceValue := reflect.MakeSlice(sSliceType, 0, 0)
    fmt.Println(sSliceType) // []main.Struct

// ******** part 3 ********
    sValue.Elem().Field(0).SetString("simple example")
    sSliceValue = reflect.Append(sSliceValue, reflect.ValueOf(sValue.Elem().Interface()))
    fmt.Println(sSliceValue) // [{simple example}]
}

在part 2中, 可以利用sliceOf將指定的型態變為slice of type,
以上我就建立了一個slice of struct並且將該type,
使用makeSlice建立出來一個sliceValue,

在part 3中, 將先前建立好的value把值set給他,
記得這裡因為new的時候它是pointer,
所以必須加上Elem()才能附值,
並且把剛剛的值append給part 2中的slice,
同樣需要注意因為slice格式為[]Struct,
所以只能append Struct的interface給他.
最後則是印出的結果.

NOTE:

  1. 因為reflect是用來在runtime的時候, 判斷interface的值, 所以在使用時須要注意型態的變化.
  2. 在過程中會用到許多類似pointer的機制, 要是沒有注意, 一不小心就會panic.
#golang #reflect #pointer #interface







你可能感興趣的文章

Level of evidence for causality - how to find causal relationship

Level of evidence for causality - how to find causal relationship

Sequelize update 後的回傳值

Sequelize update 後的回傳值

 筆記、09801 計算機網路概論-第1-B講 Computer Networks and the Internet

筆記、09801 計算機網路概論-第1-B講 Computer Networks and the Internet






留言討論