21

私は現在、Go言語でプログラミングすることを学んでいます。Goポインタを理解するのにいくつかの問題があります(そして私のC / C ++は今では遠く離れています...)。たとえば、Tour of Go#52(http://tour.golang.org/#52 )では、次のように読んでいます。

type Vertex struct {
    X, Y float64
}

func (v *Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
    v := &Vertex{3, 4}
    fmt.Println(v.Abs())
}

しかし、代わりに

func (v *Vertex) Abs() float64 {
[...]
v := &Vertex{3, 4}

私が書いた:

func (v Vertex) Abs() float64 {
[...]
v := Vertex{3, 4}

あるいは:

func (v Vertex) Abs() float64 {
[...]
v := &Vertex{3, 4}

およびその逆:

func (v *Vertex) Abs() float64 {
[...]
v := Vertex{3, 4}

まったく同じ結果が得られました。違いはありますか(メモリに関してなど)?

4

5 に答える 5

33

例で使用されているGo言語には2つの異なるルールがあります。

  1. 値レシーバーを持つメソッドからポインターレシーバーを持つメソッドを導出することが可能です。したがってfunc (v Vertex) Abs() float64、追加のメソッド実装が自動的に生成されます。

    func (v Vertex) Abs() float64 { return math.Sqrt(v.X*v.X+v.Y*v.Y) }
    func (v *Vertex) Abs() float64 { return Vertex.Abs(*v) }  // GENERATED METHOD
    

    コンパイラは、生成されたメソッドを自動的に検出します。

    v := &Vertex{3, 4}
    v.Abs()  // calls the generated method
    
  2. Goは、変数のアドレスを自動的に取得できます。次の例では:

    func (v *Vertex) Abs() float64 { return math.Sqrt(v.X*v.X+v.Y*v.Y) }
    func main() {
        v := Vertex{3, 4}
        v.Abs()
    }
    

    この式v.Abs()は、次のコードと同等です。

    vp := &v
    vp.Abs()
    
于 2013-02-26T20:44:17.507 に答える
13

違いがあります。たとえば、非ポインタレシーバーフォームは、メソッドがコピーで機能するように強制します。このように、メソッドは呼び出されたインスタンスを変更できません。コピーにのみアクセスできます。これは、たとえば時間/メモリパフォーマンス/消費などの点で効果がない可能性があります。

OTOH、インスタンスへのポインターとポインターレシーバーを備えたメソッドにより、必要に応じてインスタンスを簡単に共有(および変更)できます。

詳細はこちら

于 2013-02-26T18:27:46.537 に答える
2

違いは、参照渡しと値渡しです。

func f(v Vertex)引数でパラメータにコピーさvれます。func f(v *Vertex)既存のVertexインスタンスへのポインタが渡されます。

メソッドを使用する場合、間接参照の一部を実行できるため、メソッドfunc (v *Vertex) f()を作成して、最初にポインターを取得せずに呼び出すことができますv := Vertex{...}; v.f()。これは単なる構文糖衣、AFAIKです。

于 2013-02-26T18:27:35.547 に答える
0

これらの例には、主に2つの違いがあります。

func (v *Vertex) Abs()....

レシーバーはvの参照によって渡され、ポインターでのみこのメソッドを呼び出すことができます。

v := Vertex{1,3}
v.Abs() // This will result in compile time error
&v.Abs() // But this will work

一方で

func (v Vertex) Abs() ....

このメソッドは、ポインターと構造体の両方で呼び出すことができます。ポインターでこのメソッドを呼び出した場合でも、レシーバーは値渡しされます。

v := Vertex{1,3}
v.Abs() // This will work, v will be copied.
&v.Abs() // This will also work, v will also be copied.

func (v *Vertex)との両方を宣言できますfunc (v Vertex)

于 2014-11-05T15:06:19.953 に答える
0

仕様が言うように

xのメソッドセット(のタイプ)にmが含まれ、引数リストをmのパラメーターリストに割り当てることができる場合、メソッド呼び出しxm()は有効です。xがアドレス可能で、&xのメソッドセットにmが含まれている場合、xm()は(&x).m()の省略形です。

あなたの場合、メソッドがアドレス可能であれば、v.Abs()は&v.Abs()の省略形です。

于 2014-12-27T19:10:32.933 に答える