Golang中的方法(method)只是带有接收者(receiver)的函数(functino),通过为类型定义方法,可以实现oop编程模式。
package main
import "fmt"
type MyType struct {
Val int
}
func (m MyType) PrintVal() {
fmt.Println(m.Val)
}
func (m MyType) SetVal(val int) {
m.Val = val
}
// 定义一个以指针作为接收者的方法
func (m *MyType) SetValWitPointerReceiver(val int) {
m.Val = val
}
在定义MyType
类型及其方法后,便可以使用类似C++、Java、Python等面向对象语言的.
操作符调用相应的方法,需要注意的是如果调用方法对值进行修改,方法的接收者必须是指针类型,否则在方法内的更改不会影响到调用者,这与function的规则是一致的,因为method也是function,只是golang提供了一个方便调用的语法,自动将调用者作为function的第一个参数传递。
func main() {
m := MyType{10}
m.PrintVal() // 10
m.SetVal(20)
fmt.Println(m.Val) // 10 调用SetVal后m的Val值没有改变,因为SetVal调用时方法内的m是一个完整的拷贝
(&m).SetValWitPointerReceiver(20)
fmt.Println(m.Val) // 20 SetValWitPointerReceiver方法的接收者为指针,对指针的操作会影响到调用者本身
}
注意事项
- 为类型添加方法只允许在定义类型的包作用域内进行,或者给在当前package外定义的类型设置一个别名再为别名添加方法,否则会引发编译器错误。
// 引发编译器异常: cannot define new methods on non-local type int
func (i int) Fail() {
fmt.Println("failed")
}
// 将int用别名代替(新类型)
type CInt int
func (c CInt) Success() {
fmt.Println("success")
}
func main() {
var i int;
c := CInt(i)
c.Success() // success
}
- go中会对receiver进行必要的自动转换,但这种转换是有限制的,在使用interface时,pointer receiver可以自动转换为value receiver,但是value不能使用pointer receiver。
package main
import "fmt"
type Methods interface {
Bark()
}
type M struct {}
func (m *M) Bark() {
fmt.Println("bark")
}
func main() {
var i Methods
var m M
i = &m
// compile error: cannot use m (type M) as type Methods in assignment:
//M does not implement Methods (Bark method has pointer receiver)
i = m
i.Bark()
}