方法
golang中实例对象的方法与C++中类的公有方法类似,是一种面向对象编程的基本概念,可以说方法是与对象实例绑定的特殊函数。方法与普通函数的区别在于定义时方法有前置实例接收参数(receiver),receiver声明了方法所属的实例对象,
package main
import "fmt"
type N int
type Y int
func (arg N) test(i int) { // arg N 即receiver
fmt.Println("test", i, arg)
arg = 3
}
func (arg Y) test(i int) {
fmt.Println("test2", i, arg)
}
func main() {
var a N = 2
var b Y = 3
a.test(2)
b.test(3)
}
方法中receiver的数据类型可以为基础类型或者指针类型,当为基础类型是调用的对象将被复制,要修改实例状态的话使用指针类型*T。此外方法内部如果不需要使用实例的话,可以省略receiver中的参数名。一般来说,定义方法使用*T,减少复制成本以及防止实例对象复制锁等同步字段造成错误。
package main
import "fmt"
type N int
func (arg N) basic() {
fmt.Println("basic", arg, &arg) // arg被复制
arg++
}
func (arg *N) point() { // *arg指向本体
fmt.Println("point", *arg, arg)
(*arg)++
}
func (N) test() { // 方法内部没有调用实例可以省略参数名
fmt.Println("test")
}
func main() {
var a N = 2
fmt.Println("main", a, &a)
a.basic()
a.point()
fmt.Println("main", a, &a)
a.test()
}
方法支持指针对象实例访问,但不支持多级指针对象访问。
package main
import "fmt"
type N int
func (arg N) basic() {
fmt.Println("basic", arg, &arg) // arg被复制
arg++
}
func (arg *N) point() { // *arg指向本体
fmt.Println("point", *arg, arg)
(*arg)++
}
func main() {
var a N = 2
b := &a
a.basic()
a.point()
b.basic()
b.point()
fmt.Println("main", a, &a)
//c := &b
//c.basic() 禁止多级指针访问
}
可以像访问匿名字段那样调用其方法。
package main
import "fmt"
type N int
type Y struct {
N // 匿名字段
}
func (arg N) basic() {
fmt.Println("basic", arg, &arg) // arg被复制
arg++
}
func main() {
var a Y
a.basic()
}
方法同样可以赋予给变量,或者作为参数传递,同样可以使用表达式进行调用.
package main
import "fmt"
type ARG int
func (i ARG) test(j int) {
fmt.Println(i, j)
}
func main() {
a := ARG.test // 方法赋予给变量
var i ARG = 1
a(i, 2)
b := (*ARG).test // 方法赋予给变量
b(&i, 3)
ARG.test(i, 4) // 表达式使用
}
实例对象方法赋予给变量时,会形成闭包现象。golang会复制赋予变量时的环境,并与变量绑定,便于稍后调用。
package main
import "fmt"
type ARG int
func (i ARG) test() {
fmt.Println(i, &i)
}
func main() {
var a ARG = 100
fmt.Println(a, &a)
a++
f1 := a.test
a++
f2 := a.test
f1()
f2()
}
接口
接口是多个方法声明的集合,可嵌入其他接口类型,接口常以er作为名称的后缀。
package main
import "fmt"
type stringer interface {
toString(s string)
}
type tester interface { // 定义了一个接口,该接口包含二个方法
stringer // 嵌入其他接口
toInt(i int)
}
type data int
func (d data) toString(str string) {
fmt.Println(str, d)
}
func (d data) toInt(i int) {
fmt.Println(i, d)
}
func main() {
var d data = 100
var test tester = &d
test.toString("abc")
test.
golang支持匿名接口,可作为变量定义或者结构体成员。
package main
import "fmt"
type data int
type node struct {
data interface {
toString(str string)
}
}
func (d data) toString(str string) {
fmt.Println(str, d)
}
func (d data) toInt(i int) {
fmt.Println(i, d)
}
func main() {
var b interface {
toString(str string)
toInt(i int)
} = data(1)
b.toInt(2)
c := node{
data: b,
}
c.data.toString("abc")
}