duanbangzhou7809 2019-02-01 09:35
浏览 53
已采纳

在值上使用方法和在指针上使用方法有什么区别?

I want to know whats the difference of having methods on pointer and method on values. How both the methods work on standard structure instance as well as structure pointer.

  • 写回答

2条回答 默认 最新

  • duanre4421 2019-02-01 09:44
    关注

    Define receiver as value

    Format:

    func (r T) Xxx() {}
    

    Could call by either a value or a pointer.

    When call with pointer, the value will be passed automatically, (it actually use * to get value of the caller, and pass it).


    Define receiver as pointer

    Format:

    func (r *T) Xxx() {}
    

    In principle, should invoke with pointer only, but that's not necessary.

    Because when call with value, instead of pointer, compiler will take care of it, when possible:

    • If the value is addressable, (which is true for most data type in go).
      Then compiler will take the address (via &), and pass it automatically.
      This enable to call a pointer method with value directly, (this is pretty common in go I guess, and it makes programmer's life easier).
    • If the value is not addressable, (which is rare, but exists).
      Then need to pass the address explicitly, otherwise would get error when compile.
      e.g map's element is not addressable.

    Tips

    • Pointer caller is preferred, when define a method, if proper.
      Reasons:

      • It could modify the caller.
      • It's more lightweight for a complex caller.
    • What is passed to method, depends on the method signature, not how you call it (this is similar as with param).

      • When declare caller as pointer (r *T), it pass pointer.
      • When declare caller as value (r T), it pass a copy of original caller.
    • T itself can't be pointer.

    Code

    And, here is a go code that I wrote when learning this feature.

    Its 2 functions called in main() tests the 2 features respectively.

    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)
    ", vt, vt.AbsPointer(), "pointer", "value")        // call pointer method, with value,
        fmt.Printf("Abs of %v is %v. (Call %s method, with %s)
    
    ", 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)
    ", vt, vt.ScalePointer(10), "pointer", "value")      // call pointer method, with value,
        fmt.Printf("%v scale by 10 is: %v (Call %s method, with %s)
    ", 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)
    ", vt, (&vt).AbsValue(), "value", "pointer") // call value method, with pointer,
        fmt.Printf("Abs of %v is %v. (Call %s method, with %s)
    ", vt, vt.AbsValue(), "value", "value")      // call value method, with value,
    }
    
    func main() {
        // pointerCallerLearn()
        valueCallerLearn()
    }
    

    Just modify main(), and run via go run method_test.go, then check the output to see how it works.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器