12.1 方法声明

方法是带接收器的函数。

方法声明将标识符(方法名)绑定到方法,并将方法与接收器的基本类型相关联。

这是方法声明的语法:

func ( ReceiverParameter ) MethodName ( ParameterList ) Result FunctionBodyBlock

ReceiverParameter应该是以下两种形式之一

  • name T

  • name *T

对于非指针,非接口类型T。如果接收器的值在方法主体内未引用,则名称可以是空标识符(_),也可以完全省略。

方法语法的其余部分与函数声明基本相同。例如:

type Pt1D float32

func (p Pt1D) Dist() float32 {       // Dist 方法是为类型为 Pt1D 的接收器 p 定义的,其基本类型为 Pt1D
    if p >= 0 {
        return p
    }
    return -p
}

但是,方法声明本身不能引入类型参数,就像函数声明一样。如果接收器的基本类型是泛型类型,则接收器参数必须包括相应的类型参数,但不包括类型参数约束。接收器类型约束由接收器的基本类型定义推断出来。

例子:

type MapElement[K comparable, V any] struct {
    key    K                             // 在此示例中,不导出字段键和值,而导出类型本身
    value  V
}

func (e MapElement[K, V]) Key() K {      // 类型参数 K 和 V 与接收器 e 相关联。类型参数 K 被限制为可比较,尽管此处未显式指定。请注意,Key 方法提供对字段键的只读访问(例如,从包外部)
    return e.key
}

func (e MapElement[T, S]) Value() S {    // 为了说明,我们对类型参数使用不同的符号。T 和 S 的类型约束相同,即分别是可比较和任意
    return e.value
}

需要注意的一点是,方法必须在与接收器的基本类型相同的包中定义。也就是说,在其他方面,你不能为你不“拥有”的类型(包括所有内置类型)定义方法。

方法声明将方法绑定到其接收器的基本类型。方法名仅在T(或*T)的接收器类型的选择器内以及T的基本类型内可见。

(请注意,当接收器的类型为T(非指针,非接口类型)时,该方法仅适用于T。另一方面,当接收器的类型为T时,该方法适用于T和T。)

在Go中,使用类型作为命名空间的惯例是为了组织(相关)函数,例如,正如前面提到的空结构体类型的情况。

使用相同的示例,

type Huh struct {}            // 空结构类型,例如,没有字段

func (_ Huh) M1() {}          // 当我们不使用接收器时,不需要它的名称
func (*Huh) M2() {}           // 同上

var h Huh                     // 变量 h 的类型为 Huh
h.M1()                        // M1 仅可用作 Huh 类型变量的方法。M2 只能作为 Huh 或 *Huh 类型的变量的方法使用
h.M2()                        // 请注意,使用方法调用语法的 h.M1() 和 h.M2() 或多或少分别等同于使用函数调用语法的 Huh.M1(h) 和 Huh.M2(h)

方法的函数签名是以接收器作为其第一个参数的函数的函数签名。例如,对于以下方法,

func (ship *Ship) Move(speed float32) bool {
    // ...
}

方法 Move 的签名是

func (ship *Ship, speed float32) bool

注意,Go中没有方法字面量这种东西。可以使用具有接收器的匿名函数作为其第一个参数。

最后更新于