...このように行うことができるが、それが可能であればそれを避ける方が良いでしょう(コンパイル時にタイプとパスが分かっている場合は、フィールドselectorsとindex expressionsを使用するだけです)。
ここにデモがあります。 string
要素で指定された「深い」値を設定するヘルパー関数は次のようになります。上記の使用
func set(d interface{}, value interface{}, path ...string) {
v := reflect.ValueOf(d)
for _, s := range path {
v = index(v, s)
}
v.Set(reflect.ValueOf(value))
}
index()
関数は次のようになります。
func index(v reflect.Value, idx string) reflect.Value {
if i, err := strconv.Atoi(idx); err == nil {
return v.Index(i)
}
return v.FieldByName(idx)
}
これは、我々はそれをテストすることができる方法です:
type Foo struct {
Children []Foo
A int
}
func main() {
x := []Foo{
{
Children: []Foo{
{
Children: []Foo{
{
A: 1,
},
},
},
},
},
}
fmt.Printf("%+v\n", x)
path := "0.Children.0.Children.0.A"
set(x, 2, strings.Split(path, ".")...)
fmt.Printf("%+v\n", x)
}
出力(Go Playground上でそれを試してみてください):
[{Children:[{Children:[{Children:[] A:1}] A:0}] A:0}]
[{Children:[{Children:[{Children:[] A:2}] A:0}] A:0}]
として、出力、string
パス"0.Children.0.Children.0.A"
2
初期1
から変更することによって示される「深い」フィールドA
から見ることができます。構造体(この場合はFoo.A
とFoo.Children
)のフィールドは、エクスポートされなければならないことを
は注意(大文字で開始する必要があります)、それ以外の他のパッケージには、これらのフィールドにアクセスすることはできないだろう、とその値は、パッケージを使用して変更することができませんでしたreflect
。
f := &x[0].Children[0].Children[0]
fmt.Printf("%+v\n", f)
f.A = 3
fmt.Printf("%+v\n", f)
出力(Go Playground上でそれを試してみてください):
を前に、それは(前の例を続ける)このように行うことができますタイプと "パス" を知って反射することなく
を、
&{Children:[] A:2}
&{Children:[] A:3}
(反射なし)この一般的な解決策:
func getFoo(x []Foo, path ...string) (f *Foo) {
for _, s := range path {
if i, err := strconv.Atoi(s); err != nil {
panic(err)
} else {
f = &x[i]
x = f.Children
}
}
return
}
(再び、前の例を続ける)、それを使用する:
path = "0.0.0"
f2 := getFoo(x, strings.Split(path, ".")...)
fmt.Printf("%+v\n", f2)
f2.A = 4
fmt.Printf("%+v\n", f2)
出力(Go Playground上でそれを試してみてください):
&{Children:[] A:3}
&{Children:[] A:4}
をしかし、我々は唯一のint
インデックスを扱っている場合ことに注意してください、 path
を...string
(これは[]string
)と宣言することはもはや意味をなさないが、int
スライスはより意味をなさないだろう。
ネストされた構造体では、 'A.B.C ...'を実行するだけです。マップ、配列、またはスライスを使うと、 'a [0] [" x "] ...'を実行するだけです。他の慣用的なショートカットはありません。 – Nadh
Pythonのリスト内包は、このような機能操作を行うための別の方法を提供します。 [Goでのリスト内包に関する別の質問に対処するこの回答(http://stackoverflow.com/a/27848524/539810)は、それが可能だが価値がないことを説明しているので、読む価値がある。 –