この Codelab では、Goの標準ライブラリのひとつである reflect
パッケージを学びます。
以下のゴールを達成して、Goでメタプログラミングができるようになりましょう!
reflect パッケージは、Goの標準ライブラリのひとつです。 reflect パッケージを使うと、プログラムは、自身を鏡に反射(reflection)するように、ランタイムの型や値を見ることができるようになります。
そして、型や値を見るだけだなく、ランタイムでそれらを変更することができます。
ランタイムの型の情報を取得するには reflect.TypeOf()
を使用します。
取得できる型情報は Type
interface を実装しています。
package main
import (
"fmt"
"reflect"
)
type person struct {
name string
}
func main() {
p := person{
name: "にゅも太郎",
}
t := reflect.TypeOf(p)
fmt.Println(t.Name()) // person
}
ランタイムの値の情報を取得するには reflect.ValueOf()
を使用します。
取得できる値の情報は Value
struct を実装しています。
package main
import (
"fmt"
"reflect"
)
type person struct {
name string
}
func main() {
p := &person{
name: "にゅも太郎",
}
v := reflect.ValueOf(p)
fmt.Println(v.Elem()) // {にゅも太郎}
}
ある struct A を、別の struct Bにコピーすることを考えます。 もっともシンプルな方法は、すべてのフィールドに対して代入をおこなうことです。
package main
import (
"fmt"
)
type Person struct {
Name string
Age int
}
func main() {
p1 := Person{Name: "Alice", Age: 20}
p2 := Person{}
copyPerson(&p1, &p2)
fmt.Println(p2) // {Alice 20}
}
func copyPerson(src, dst *Person) {
dst.Name = src.Name
dst.Age = src.Age
}
この方法には、以下のような問題があります。
Person
のフィールドが増えると copyPerson
のコードを変更する必要があるreflect パッケージを使ってこの問題を解決してみましょう。
任意の型の struct をコピーできる copyStruct
関数を実装してみましょう。 雛形のコードはこちらです。
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
DNA string
Soul string `copyable:"false"`
}
type Food struct {
Name string
Kind string
secretIngredient string
}
func main() {
p1 := Person{Name: "Alice", DNA: "ALICE_DNA", Soul: "ALICE_SOUL"}
p2 := Person{}
f1 := Food{Name: "Icecream", Kind: "Sweet", secretIngredient: "Salt"}
f2 := Food{}
copyStruct(&p1, &p2)
copyStruct(&f1, &f2)
fmt.Println(p2) // {Alice 20}
fmt.Println(f2) // {Icecream Sweet}
}
// TODO: implement
func copyStruct() {}
any
を使いましょうreflect.ValueOf()
を使いましょうValue.Elem()
を使いますValue.NumField()
を使うと、フィールドの数を取得できますValue.Filed(index)
を使うと、その index
のフィールドを取得できますValue.CanSet()
を使いましょうValue.Set(Value)
を使うと、値情報を別の値情報にマッピングできますフィールドが copyable:"false"
の Struct Tag をもつ場合、代入をスキップしてみましょう。
reflect パッケージを使ったメタプログラミングには、ランタイムの振る舞いを変える以外にも、以下のように使うことができます。 関連のOSSのソースコードなどを読んでみましょう。
go generate
を使って、コード生成する