[解決済み】golangでデータ構造をディープコピーする
質問内容
あるデータ構造のインスタンスを複製したい。goにはビルトインがないので、サードパーティのライブラリを使っています。
https://github.com/emirpasic/gods
.
例えば、ハッシュセットでディープコピーしてみたり。
var c, d hashset.Set
c = *hashset.New()
c.Add(1)
deepcopy.Copy(d, c)
c.Add(2)
fmt.Println(c.Contains(2))
fmt.Println(d.Contains(2))
fmt.Println(c.Contains(1))
fmt.Println(d.Contains(1))
しかし、ハッシュセットの中身は全くコピーされません。ディープコピーモジュールがエクスポートされていない値をコピーできないことは知っていますが、ライブラリには組み込みの "copy コンストラクタ" がないので、ライブラリでデータ構造のインスタンスをコードを修正せずに完全に複製することはできないということでしょうか?(同様の問題は、私が調べた他のいくつかのライブラリでも発生します)。
私はgolangの初心者ですが、同じようなことは例えばC++で簡単に実現できるため、正しいとは思えません。私は自分自身のバージョンを書いたり、彼らのコードを修正することができることを知っていますが、それは予想よりもあまりにも多くの仕事であり、それが慣用的な方法があるべきと考える理由です。
PS: 「そんな機能は必要ない」と言う人のために説明すると、私はいくつかのデータ構造を持つ複雑な状態を並列計算スレッドに分散しており、それらは状態を直接使用するので互いに干渉してはいけません。
どのように解決するのですか?
残念ながら、Goでこれを行う方法はありません。最初に思い浮かぶツールはリフレクションです(パッケージ
reflect
しかし、リフレクションを使うと、エクスポートされていないフィールドを読むことはできても、それを設定することはできないのです。参照
未エクスポートのフィールドを持つ構造体をクローンする方法は?
エクスポートされていないフィールドを持つ構造体をクローンする唯一の方法は、パッケージの
unsafe
(例はこちらをご覧ください。
golang/reflect の unexported フィールドにアクセスしますか?
) ですが、その名の通り、これは
安全でない
なるべく使わないでください。を使用して作成されたプログラムは
unsafe
は、新しい Go リリースで動作し続ける保証はありませんし、どのプラットフォームでも同じ動作をする保証はありません。
一般的に Go でクローンをサポートする唯一かつ適切な方法は、パッケージ自体がそのような操作をサポートしている場合です。
注意点その1。
このことは、一部の
具体的
の場合、新しい値を作成し、その状態を手動で構築することで、クローンを模倣することができません。例えば
map
を作成し、元のマップのキーと値のペアを繰り返し、新しいマップに設定することです。
注意点その2。
未エクスポートのフィールドを持つ構造体の正確なコピーを作成するには、次のようにします。 代入 を別の(同じ型の)構造体変数にコピーすると、エクスポートされないフィールドも適切にコピーされます。
この例のように。
type person struct {
Name string
age *int
}
age := 22
p := &person{"Bob", &age}
fmt.Println(p)
p2 := new(person)
*p2 = *p
fmt.Println(p2)
と出力されます(試しに 囲碁プレイグラウンド ):
&{Bob 0x414020}
&{Bob 0x414020}
を使って一般化することもできます。
reflect
具体的な型に依存することなく
type person struct {
Name string
age *int
}
age := 22
p := &person{"Bob", &age}
fmt.Println(p)
v := reflect.ValueOf(p).Elem()
vp2 := reflect.New(v.Type())
vp2.Elem().Set(v)
fmt.Println(vp2)
これを 囲碁の遊び場 .
しかし、できないこと
を変更することです。
person.age
unexportedフィールドが他のものを指すようにします。宣言するパッケージの助けがなければ、これは
nil
または同じポインタ値(元のフィールドと同じオブジェクトを指す)。
関連もご覧ください。 golangでオブジェクトをディープコピーする素早い方法
関連
-
[解決済み] go run: 非メインパッケージは実行できません
-
GOROOT に xxx というパッケージがないというエラーが GoLand から報告される
-
コンパイル: バージョン "" は go ツールのバージョン "" と一致しません。
-
[解決済み] このキャスティングはgolangで行われているのでしょうか?
-
[解決済み] 全モジュールのアップデートを行う
-
[解決済み] ディープコピーとシャローコピーの違いは何ですか?
-
[解決済み] Goでオブジェクトの型を見つけるには?
-
[解決済み] デュレーションと整数を掛け合わせる方法は?
-
[解決済み] GOPATHとGOROOTの値はどうすればよいですか?
-
[解決済み】Goの構造体のスタックとヒープ割り当て、およびガベージコレクションとの関連性
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] 構造体のマップのデフォルト値は何ですか?
-
[解決済み] GORMでレコードを作成・更新するには?
-
[解決済み] panic: ランタイムエラー:Goのインデックスが範囲外
-
[解決済み] go言語でUUIDを生成する方法はありますか?
-
[解決済み] mod initは新しいフォルダを作成しますか? パスの意味は?
-
[解決済み] golangでnilはどういう意味ですか?
-
[解決済み] gofmtの使い方を教えてください。
-
[解決済み] ゼロ終端のバイト配列を文字列に変換するにはどうすればよいですか?
-
[解決済み】init()関数はいつ実行されるのですか?
-
[解決済み】gopathを使わずにローカルパッケージをインポートする方法