1. ホーム
  2. go

[解決済み] スライスは値で渡されるのか?

2023-04-25 16:20:48

質問

Goで、巡回セールスマン問題のためのスクランブルスライス関数を作ろうとしています。これをやっている間、私は私が与えたスライスを編集し始めたとき、私がそれを渡すたびにスクランブル関数が異なっていることに気づきました。

いくつかのデバッグの後、それは私が関数内のスライスを編集したためであることがわかりました。しかし、Go は "値で渡す" 言語であるはずなので、これはどのようにして可能なのでしょうか?

https://play.golang.org/p/mMivoH0TuV

私が言いたいことを示すために、プレイグラウンドリンクを提供しました。 27 行目を削除すると、それを残した場合とは異なる出力が得られますが、この関数は引数として渡されたときにスライスの独自のコピーを作成することになっているため、違いは生じないはずです。

どなたかこの現象を説明していただけませんか?

どのように解決するのですか?

Goではすべてが値で渡され、スライスもそうです。しかし、スライスの値というのは ヘッダ であり、スライス値には実際に要素が格納されている配列へのポインタのみが含まれます。スライス値にはその要素は含まれません (配列とは異なります)。

そのため、関数にスライスを渡すと、ポインタを含むこのヘッダからコピーが作成され、同じバックアレイを指すことになります。スライスの要素を変更することは、バッキング配列の要素を変更することを意味しますので、同じバッキング配列を共有するすべてのスライスは、その変更を "観察"します。

スライスのヘッダーに何があるのかを確認するために reflect.SliceHeader という型があります。

type SliceHeader struct {
    Data uintptr
    Len  int
    Cap  int
}

関連する/重複する可能性のある質問を参照してください。 Golangの関数パラメータはコピーオンライトで渡されるのでしょうか?

ブログ記事を読む Go スライス: 使用法と内部構造