1. 方法定义

    Golang 方法总是绑定对象实例,并隐式将实例作为第一实参 (receiver)。

    一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针。

    所有给定类型的方法属于该类型的方法集。

    1. 参数和返回值可以省略
    1. package main
    2. type Test struct{}
    3. // 无参数、无返回值
    4. func (t Test) method0() {
    5. }
    6. // 单参数、无返回值
    7. func (t Test) method1(i int) {
    8. }
    9. // 多参数、无返回值
    10. func (t Test) method2(x, y int) {
    11. }
    12. // 无参数、单返回值
    13. func (t Test) method3() (i int) {
    14. return
    15. }
    16. // 多参数、多返回值
    17. func (t Test) method4(x, y int) (z int, err error) {
    18. return
    19. }
    20. // 无参数、无返回值
    21. func (t *Test) method5() {
    22. }
    23. // 单参数、无返回值
    24. func (t *Test) method6(i int) {
    25. }
    26. // 多参数、无返回值
    27. func (t *Test) method7(x, y int) {
    28. }
    29. // 无参数、单返回值
    30. func (t *Test) method8() (i int) {
    31. return
    32. }
    33. // 多参数、多返回值
    34. func (t *Test) method9(x, y int) (z int, err error) {
    35. return
    36. }
    37. func main() {}

    下面定义一个结构体类型和该类型的一个方法:

    1. golang : golang@golang.com
    2. go : go@go.com

    解释: 首先我们定义了一个叫做 User 的结构体类型,然后定义了一个该类型的方法叫做 Notify,该方法的接受者是一个 User 类型的值。要调用 Notify 方法我们需要一个 User 类型的值或者指针。

    在这个例子中当我们使用指针时,Go 调整和解引用指针使得调用可以被执行。注意,当接受者不是一个指针时,该方法操作对应接受者的值的副本(意思就是即使你使用了指针调用函数,但是函数的接受者是值类型,所以函数内部操作还是对副本的操作,而不是指针操作。

    我们修改 Notify 方法,让它的接受者使用指针类型:

    1. package main
    2. import (
    3. "fmt"
    4. )
    5. //结构体
    6. type User struct {
    7. Name string
    8. Email string
    9. }
    10. //方法
    11. func (u *User) Notify() {
    12. fmt.Printf("%v : %v \n", u.Name, u.Email)
    13. }
    14. func main() {
    15. // 值类型调用方法
    16. u1 := User{"golang", "golang@golang.com"}
    17. u1.Notify()
    18. // 指针类型调用方法
    19. u3.Notify()
    20. }

    输出结果:

    方法不过是一种特殊的函数,只需将其还原,就知道 receiver T 和 *T 的差别。

    1. package main
    2. import "fmt"
    3. type Data struct {
    4. x int
    5. }
    6. func (self Data) ValueTest() { // func ValueTest(self Data);
    7. fmt.Printf("Value: %p\n", &self)
    8. }
    9. func (self *Data) PointerTest() { // func PointerTest(self *Data);
    10. fmt.Printf("Pointer: %p\n", self)
    11. }
    12. func main() {
    13. d := Data{}
    14. p := &d
    15. fmt.Printf("Data: %p\n", p)
    16. d.ValueTest() // ValueTest(d)
    17. d.PointerTest() // PointerTest(&d)
    18. p.ValueTest() // ValueTest(*p)
    19. p.PointerTest() // PointerTest(p)
    20. }

    输出:

    1. Data: 0xc42007c008
    2. Value: 0xc42007c018
    3. Pointer: 0xc42007c008
    4. Value: 0xc42007c020
    5. Pointer: 0xc42007c008

    1.1.2. 普通函数与方法的区别

    1.对于普通函数,接收者为值类型时,不能将指针类型的数据直接传递,反之亦然。

    2.对于方法(如struct的方法),接收者为值类型时,可以直接用指针类型的变量调用方法,反过来同样也可以。

    1. valueIntTest: 12
    2. pointerIntTest: 15
    3. hello world
    4. hello world
    5. hello golang