2

次のようなコードを見ると、少し混乱します。

bigBox := &BigBox{}
bigBox.BubbleGumsCount = 4          // correct...
bigBox.SmallBox.AnyMagicItem = true // also correct

bigBox := &BigBox{}なぜ、またはいつ、代わりにやりたいのbigBox := BigBox{}ですか? ある意味より効率的ですか?

コードサンプルはhereから取得されました。

サンプル No.2:

package main

import "fmt"

type Ints struct {
  x int
  y int
}

func build_struct() Ints {
  return Ints{0,0}
}

func build_pstruct() *Ints {
  return &Ints{0,0}
}

func main() {
  fmt.Println(build_struct())
  fmt.Println(build_pstruct())
}

サンプル番号 3: (この例では、BigBox を構造体として直接使用せずに、なぜ &BigBox を使用するのでしょうか?)

func main() {
  bigBox := &BigBox{}
  bigBox.BubbleGumsCount = 4 
  fmt.Println(bigBox.BubbleGumsCount)
}

build_struct バリアントの代わりに build_pstruct を呼び出す理由はありますか? それが私たちがGCを持っている理由ではありませんか?

4

5 に答える 5

3

bb := &BigBox{}構造体を作成しますが、変数をそれへのポインターに設定します。と同じbb := new(BigBox)です。一方、bb := BigBox{}bb を直接 BigBox 型の変数にします。ポインターが必要な場合 (おそらくポインターを介してデータを使用するため)、bb をポインターにすることをお勧めします。そうしないと&bb、大量の書き込みを行うことになります。データを構造体として直接使用する場合は、bb を構造体にする必要があります。それ以外の場合は、で逆参照することになります*bb

それは問題の要点から外れていますが、通常は、オブジェクトを作成してから更新することで段階的にデータを作成するよりも、一度にデータを作成する方が適切です。

bb := &BigBox{
    BubbleGumsCount: 4,
    SmallBox: {
        AnyMagicItem: true,
    },
}
于 2013-09-22T09:34:04.063 に答える
1

違いは、参照オブジェクトの作成 (アンパサンドを使用) と値オブジェクトの作成 (アンパサンドを使用しない) の違いです。

値と参照型の受け渡しの一般的な概念について、わかりやすい説明があります。参照による受け渡しと値による受け渡しの違いは何ですか?

Go here に関して、これらの概念についていくつかの議論があります... http://www.goinggo.net/2013/07/understanding-pointers-and-memory.html

于 2013-09-21T22:29:01.073 に答える
1

&BigBox{}一般に、 aとの間に違いはありませんBigBox{}。Go コンパイラは、セマンティクスが正しい限り、好きなことを自由に行うことができます。

func StructToStruct() {
    s := Foo{}
    StructFunction(&s)
}

func PointerToStruct() {
    p := &Foo{}
    StructFunction(p)
}

func StructToPointer() {
    s := Foo{}
    PointerFunction(&s)
}

func PointerToPointer() {
    p := &Foo{}
    PointerFunction(p)
}

//passed as a pointer, but used as struct
func StructFunction(f *Foo) {
    fmt.Println(*f)
}

func PointerFunction(f *Foo) {
    fmt.Println(f)
}

組み立ての概要:

  • StructToStruct:13回線、割付なし
  • PointerToStruct:16回線、割付なし
  • StructToPointer: 20 行、ヒープ割り当て
  • PointerToPointer: 12 行、ヒープ割り当て

完全なコンパイラでは、*ToStruct関数は関数と同じになり*ToPointerます。Go のエスケープ解析は、ポインターがモジュールの境界を越えてもエスケープするかどうかを判断するのに十分です。どちらの方法が最も効率的であるかは、コンパイラーが行う方法です。

マイクロ最適化に本当に興味がある場合は、構文がセマンティクス (構造体として使用される構造体、ポインターとして使用されるポインター) と一致する場合に Go が最も効率的であることに注意してください。または、それを忘れて、使用される方法で変数を宣言することもできます。ほとんどの場合、あなたは正しいでしょう。

注:Fooが本当に大きい場合は、PointerToStructヒープが割り当てられます。仕様はそれを行うことさえStructToStruct許されていますが、私はそれを実現できませんでした。ここでの教訓は、コンパイラは必要なことを何でも行うということです。レジスタの詳細がコードから隠されているのと同様に、ヒープ/スタックの状態も隠されています。コンパイラがヒープをどのように使用するかを知っていると思うので、コードを変更しないでください。

于 2013-09-25T21:01:00.653 に答える