2012-06-11 6 views
7

私はGoを学んでいますが、私はポインターをいつ使うのか少し混乱しています。具体的には、関数からstructを返すときは、いつstructインスタンス自体を返すのが適切で、いつstructにポインタを返すのが適切なのでしょうか?構造体へのポインタを返すのは良い考えですか?

例コード:

type Car struct { 
    make string 
    model string 
} 

func Whatever() { 
    var car Car 

    car := Car{"honda", "civic"} 

    // ... 

    return car 
} 

私はポインタを返すようにしたいと思うような状況で、どこがはしたくないでしょうか?親指の良いルールはありますか?

+4

これはC言語ではありません。 –

+0

同じルールは適用されませんか? – Carson

+2

いいえ、異なる言語のための異なる規則。すべての言語には注意点がありますが、私は個人的にはGoを知らないので、私はそれについて話すことはできませんが、C言語では、スタックに割り当てられたオブジェクトへのポインタを返すことは巨大であるということはわかります。 –

答えて

12

あなたが心に留めておきたい2つあります、パフォーマンスとAPI。

車はどのように使用されますか?それは状態を持っているオブジェクトですか?それは大きな構造体ですか?残念ながら、私は車が何であるか分からないときは答えが不可能です。正直なところ、他の人が何をしてそれらをコピーするかを見るのが最善の方法です。結局のところ、あなたはこのようなことに対する感情を得る。ここで標準ライブラリの3つの例を説明し、なぜ彼らが行ったことを使ったのかを説明します。

  1. hash/crc32crc32.NewIEEE()関数ポインタタイプ返す(実際、インターフェースを、しかし、根本的なタイプのポインタです)。ハッシュ関数のインスタンスには状態があります。ハッシュに情報を書き込むときにデータを集計するので、Sum()メソッドを呼び出すと、その1つのインスタンスの状態が得られます。

  2. timetime.Date関数は、Time構造体を返します。どうして?時間は時間です。それは状態がありません。これは整数のようなもので、それらを比較したり、それらのプリフォームの数学を作成したりすることができます。APIデザイナーは、時間の修正によって現在のものが変更されることはないが、新しいものを作ることになります。ライブラリーのユーザーとして、今から1ヶ月後には、新しい時間オブジェクトが必要です。現在のものを変更することはできません。時間もわずか3ワードです。言い換えれば、それは小さく、ポインタを使用するとパフォーマンスは向上しません。

  3. math/bigbig.NewInt()は興味深いものです。 big.Intを変更すると、新しいものが必要になることが多いことにかなり同感できます。 big.Intには内部状態がないので、なぜそれがポインタですか?答えは単にパフォーマンスです。プログラマーは、大きなintが...大きいことに気づいた。あなたが数学的操作を行うたびに常に割り振ることは実用的ではないかもしれません。そこで、彼らはポインタを使用してプログラマが新しい空間をいつ割り当てるかを決めることにしました。

私はあなたの質問に答えましたか?おそらくそうではありません。それは設計上の決定であり、ケースバイケースでそれを把握する必要があります。私は私自身のライブラリを設計しているときに標準ライブラリを参考にしています。それは本当にすべての判断になり、どのようにクライアントコードがあなたのタイプを使用すると思いますか。

+1

を表示したような独自の関数を定義する必要があります。これが本当に良い答えであることを数回読んでいました。ありがとうございました。 – Carson

+0

偉大な答え。私は新しくGoであり、IRCの#go-nutsからStephenによってここに紹介されました。 –

1

は非常にlosely、例外は、特定の状況下に表示する可能性がある:

  • 戻り、それは(いくつかの単語を超えない)本当に小さい値。
  • コピーオーバーヘッドがパフォーマンスを大幅に損なう場合は、ポインタを返します(サイズは大量です)。
2

オブジェクト指向スタイルを模倣したいときには、状態を保存する「オブジェクト」とオブジェクトを変更できる「メソッド」がある場合は、「コンストラクタ」関数が返されます構造体へのポインタ(他のオブジェクト指向言語のように "オブジェクト参照"と考える)。 Mutatorメソッドは、 "オブジェクト"のフィールドを変更するために、struct型の代わりにstruct-to-the-struct型のメソッドでなければならないので、structの代わりにstructへのポインタを持つと便利ですすべての "メソッド"がそのメソッドセットに入るようにします。 Javaでこのような何かを模倣する例えば

、:

class Car { 
    String make; 
    String model; 
    public Car(String myMake) { make = myMake; } 
    public setMake(String newMake) { make = myMake; } 
} 

あなたが行くにはこのようなものをしばしば見ること:

type Car struct { 
    make string 
    model string 
} 
func NewCar(myMake string) *Car { 
    return &Car{myMake, ""} 
} 
func (self *Car) setMake(newMake string) { 
    self.make = newMake 
} 
+0

ですから、 'new'キーワードを使用しないでください。私はあなたが例示したように参照を返す必要がありますか?私はあなたの事例に混乱しています。 – Carson

+0

@Carson:まあ、 'new'を使うことができますが、' new'は型のゼロ値に値を初期化します。構造体はすべてのフィールドがゼロ値に初期化されています。これは、すべての型に対して有効に初期化された値ではない可能性があります。あなたの型を初期化するための値が0であれば、単に 'new'を使うことができます。あなたのタイプがカスタムの "コンストラクタ"を必要とする場合は、私が – newacct