リフレクションを使用して Go スライスに追加: 隠れた問題を明らかにする
Go のリフレクション パッケージを使用して新しい要素をスライスに追加すると、予期しない動作が発生する元のスライスが影響を受けない場合に発生する可能性があります。これは、次のコード スニペットで明らかです:
func appendToSlice(arrPtr interface{}) { valuePtr := reflect.ValueOf(arrPtr) value := valuePtr.Elem() value = reflect.Append(value, reflect.ValueOf(55)) fmt.Println(value.Len()) // prints 1 } func main() { arr := []int{} appendToSlice(&arr) fmt.Println(len(arr)) // prints 0 }
スライスされた値に要素を追加しているにもかかわらず、元のスライスは元の長さのゼロを保持します。この不可解な矛盾には説明が必要です。
リフレクションとスライス操作
リフレクションを使用すると、スライスを含むデータ構造を実行時に検査および操作できます。 Reflect.Append 関数は、append と同様に、スライス値と新しい要素を受け取り、更新された要素を含む新しいスライス値を返します。ただし、この操作は元のスライス参照を変更しません。
提供されたコードでは、reflect.Append ステートメントは新しいreflect.Value を value 変数に割り当て、スライスへの元の参照を効果的に置き換えます。値自体が更新される間、元の arr ポインターは変更されないため、main 関数の arr スライスの長さは変更されません。
元のスライスの更新
To元のスライスを更新するには、Value.Set メソッドを使用する必要があります。このメソッドは、スライスされた値の指定されたインデックスの値を新しい値に置き換えます。この例では、スライス全体を、reflect.Append:
func appendToSlice(arrPtr interface{}) { valuePtr := reflect.ValueOf(arrPtr) value := valuePtr.Elem() value.Set(reflect.Append(value, reflect.ValueOf(55))) fmt.Println(value.Len()) // prints 1 }
によって返された新しい値で置き換える必要があります。この変更により、元のスライスが出力に反映されて更新されるようになりました。
結論
リフレクションを使用してスライスに追加するには、従来の追加操作よりも少し細かいニュアンスが必要です。重要な点は、リフレクション操作は値のコピーを操作するため、元の値を更新するには、Value.Set メソッドを使用して明示的に値を設定する必要があるということです。
以上がReflection の「reflect.Append」が元の Go スライスを変更しないのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。