引数、型へのポインタを持つ関数があります。
type bar struct{...}
func foo(arg *bar)
間に違いはありますか?
var b bar
foo(&b)
と
b := new(bar)
foo(b)
newを使用すると、割り当てが作成されます。
いいえ、違いはありません。Cとは異なり、Goは、ローカルで作成された変数へのポインターを指定できることを明示的に示しています。
ドキュメントから:
Cとは異なり、ローカル変数のアドレスを返すことはまったく問題ないことに注意してください。変数に関連付けられたストレージは、関数が戻った後も存続します
どちらも、同じデフォルト値で初期化された同じオブジェクトへの同じポインタを表す必要があります。
仕様には次のように記載されています。
後
type T struct { i int; f float64; next *T }
t := new(T)
以下が成り立ちます:
t.i == 0
t.f == 0.0
t.next == nil
後も同じことが言えます
var t T
また:
複合リテラルのアドレスを取得すると(§アドレス演算子)、リテラルの値の一意のインスタンスへのポインターが生成されます。
var pointer *Point3D = &Point3D{y: 1000}
特定の状況では違いがあります。new(T)
、名前が示すように、タイプTの新しいインスタンスを返しますが、これvar b T
は単一のインスタンスであり、一度限りです(エラー、実際にはその存続期間が終了するまで==スコープ外になり、到達できません...)。
このループを検討してください
var b bar
for i := 0; i < 10; i++ {
foo(&b)
}
vs
var b *bar
for i := 0; i < 10; i++ {
b = new(b)
foo(b)
}
後者の場合、foo
たとえば、それをあるコンテナに格納すると、既存のarg
インスタンスが10個発生しますがbar
、前者の場合は、変数に-が1つだけありますb
。
もう1つの違いは、パフォーマンスにあります。変数b
は、完全に静的なグローバル変数であるか、通常、関数/メソッド呼び出しレコード(通常はスタックフレームのファンシーな名前)の静的に既知のオフセットに配置されます。new
OTOHは、コンパイラーによって最適化されていない場合、メモリーアロケーター呼び出しです。このような呼び出しには、ゼロ以外の時間がかかります。ループで作成され、実際には必要ない場合は、コードパスの速度が著しく低下する可能性があります。