为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
德玛西亚99 2023-06-05 16:58:28
我想知道在指针上使用方法和在值上使用方法有什么区别。这两种方法如何在标准结构实例和结构指针上工作。
查看完整描述

2 回答

?
慕雪6442864

TA贡献1812条经验 获得超5个赞

将接收者定义为值

格式:

func (r T) Xxx() {}

可以通过值或指针调用。

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


将接收器定义为指针

格式:

func (r *T) Xxx() {}

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

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

  • 如果该值是可寻址的,(对于 go 中的大多数数据类型都是如此)
    然后编译器将获取地址(通过&),并自动传递它。
    这使得可以直接调用具有值的指针方法,(我猜这在 go 中很常见,它使程序员的生活更轻松)

  • 如果该值不可寻址,(这种情况很少见,但存在)
    然后需要显式传递地址,否则编译时会出错。
    egmap的元素不可寻址。


尖端

  • 如果合适,在定义方法时首选指针调用者。
    原因:

    • 它可以修改调用者。

    • 对于复杂的调用者来说,它更轻量级。

  • 传递给方法的内容取决于方法签名,而不是您如何调用它(这与参数类似)

    • 当将调用者声明为指针时(r *T),它传递指针。

    • 当将调用者声明为 value 时(r T),它会传递原始调用者的副本。

  • T本身不能是指针。


代码

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

它调用的2个函数main()分别测试2个特性。

方法_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()

}

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


查看完整回答
反对 回复 2023-06-05
?
慕森卡

TA贡献1806条经验 获得超8个赞

它们之间的最大区别是价值接收者被复制*。所以如果你想改变你的接收器,你必须使用指针。观察:


package main


import (

    "fmt"

)


type Person struct {

  Age int

}


func (p Person) GrowUp1() {

  p.Age++

}


func (p *Person) GrowUp2() {

  p.Age++

}


func main() {

  p := Person{Age: 20}

  fmt.Println(p)


  p.GrowUp1()

  fmt.Println(p)



  p.GrowUp2()

  fmt.Println(p)

}

// {20}

// {20}

// {21}

* 当然,指针也会被复制。但由于它们是指针,指针的副本仍然指向同一个对象。


查看完整回答
反对 回复 2023-06-05
  • 2 回答
  • 0 关注
  • 93 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信