Go 值方法和指针方法有什么区别?

Lah*_*hne 5 go

我想知道指针上的方法和值上的方法有什么区别。这两种方法如何在标准结构实例和结构指针上工作。

Eri*_*ang 6


将接收者定义为值

格式:

func (r T) Xxx() {}
Run Code Online (Sandbox Code Playgroud)

可以通过值或指针进行调用。

当使用指针调用时,值将自动传递(它实际上用于*获取调用者的值,并传递它)。


将接收者定义为指针

格式:

func (r *T) Xxx() {}
Run Code Online (Sandbox Code Playgroud)

原则上,应该仅使用指针调用,但这不是必需的。

因为当使用值而不是指针调用时,编译器会在可能的情况下处理它:

  • 如果该值是可寻址的(对于 go 中的大多数数据类型都是如此)
    然后编译器将获取地址(通过&),并自动传递它。
    这使得能够直接调用带有值的指针方法(我猜这在 go 中很常见,并且它使程序员的生活更轻松)
  • 如果该值不可寻址(这种情况很少见,但存在)
    然后需要显式地传递地址,否则编译时会出错。
    egmap的元素不可寻址。

尖端

  • 如果合适的话,在定义方法时,首选指针调用者。
    理由:

    • 它可以修改调用者。
    • 对于复杂的调用者来说它更加轻量级。
  • 传递给方法的内容取决于方法签名,而不是您如何调用它(这与 param 类似)

    • 当将调用者声明为指针时(r *T),它传递指针。
    • 当将调用者声明为 value 时(r T),它​​传递原始调用者的副本。
  • T本身不能是指针。

代码

并且,这是我在学习此功能时编写的代码。

它调用的 2 个函数main()分别测试这 2 个功能。

method_learn.go:

// method - test
package main

import (
    "fmt"
    "math"
)

type Vertex struct {
    x float64
    y float64
}

// abs, with pointer caller,
func (v *Vertex) AbsPointer() float64 {
    return math.Sqrt(v.x*v.x + v.y*v.y)
}

// scale, with pointer caller,
func (v *Vertex) ScalePointer(f float64) *Vertex {
    v.x = v.x * f
    v.y = v.y * f

    return v
}

// abs, with value caller,
func (v Vertex) AbsValue() float64 {
    return math.Sqrt(v.x*v.x + v.y*v.y)
}

// test - method with pointer caller,
func pointerCallerLearn() {
    vt := Vertex{3, 4}
    fmt.Printf("Abs of %v is %v. (Call %s method, with %s)\n", vt, vt.AbsPointer(), "pointer", "value")        // call pointer method, with value,
    fmt.Printf("Abs of %v is %v. (Call %s method, with %s)\n\n", vt, (&vt).AbsPointer(), "pointer", "pointer") // call pointer method, with pointer,

    // scala, change original caller,
    fmt.Printf("%v scale by 10 is: %v (Call %s method, with %s)\n", vt, vt.ScalePointer(10), "pointer", "value")      // call pointer method, with value,
    fmt.Printf("%v scale by 10 is: %v (Call %s method, with %s)\n", vt, (&vt).ScalePointer(10), "pointer", "pointer") // call pointer method, with pointer,
}

// test - method with value caller,
func valueCallerLearn() {
    vt := Vertex{3, 4}
    fmt.Printf("Abs of %v is %v. (Call %s method, with %s)\n", vt, (&vt).AbsValue(), "value", "pointer") // call value method, with pointer,
    fmt.Printf("Abs of %v is %v. (Call %s method, with %s)\n", vt, vt.AbsValue(), "value", "value")      // call value method, with value,
}

func main() {
    // pointerCallerLearn()
    valueCallerLearn()
}
Run Code Online (Sandbox Code Playgroud)

只需修改main()并通过 运行go run method_test.go,然后检查输出以了解其工作原理。