方法是带接收器的函数。
方法声明将标识符(方法名)绑定到方法,并将方法与接收器的基本类型相关联。
这是方法声明的语法:
复制 func ( ReceiverParameter ) MethodName ( ParameterList ) Result FunctionBodyBlock
ReceiverParameter应该是以下两种形式之一
对于非指针,非接口类型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中没有方法字面量这种东西。可以使用具有接收器的匿名函数作为其第一个参数。