Go函数
Go语言 方法
- Golang 方法总是绑定对象实例,并隐式将实例作为第一实参 (receiver)。 - 一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针。 - 所有给定类型的方法属于该类型的方法集。 - 方法是一种特殊的函数。 只能为当前包内命名类型定义方法。 参数 receiver 可任意命名。如方法中未曾使用 ,可省略参数名。 参数 receiver 类型可以是 T 或 *T。基类型 T 不能是接口或指针。 不支持方法重载,receiver 只是参数签名的组成部分。 可用实例 value 或 pointer 调用全部方法,编译器自动转换。 ## 方法定义 ```go func (recevier type) methodName(参数列表)(返回值列表){} // 无参数、无返回值 func (t Test) method0() {} // 单参数、无返回值 func (t Test) method1(i int) {} // 多参数、无返回值 func (t Test) method2(x, y int) {} // 无参数、无返回值 func (t *Test) method5() {} // 无参数、单返回值 func (t Test) method3() (i int) { return } // 多参数、多返回值 func (t Test) method4(x, y int) (z int, err error) { return } // 单参数、无返回值 func (t *Test) method6(i int) {} // 多参数、无返回值 func (t *Test) method7(x, y int) {} // 无参数、单返回值 func (t *Test) method8() (i int) { return } // 多参数、多返回值 func (t *Test) method9(x, y int) (z int, err error) { return } ``` - 下面定义一个结构体类型和该类型的一个方法: ```go //结构体 type User struct { Name string Email string } //方法 func (u User) Notify() { fmt.Printf("%v : %v \n", u.Name, u.Email) } func main() { // 值类型调用方法 u1 := User{"golang", "golang@golang.com"} u1.Notify() // golang : golang@golang.com // 指针类型调用方法 u2 := User{"go", "go@go.com"} u3 := &u2 u3.Notify() // go : go@go.com } //首先我们定义了一个叫做 User 的结构体类型,然后定义了一个该类型的方法叫做 Notify,该方法的接受者是一个 User 类型的值。要调用 Notify 方法我们需要一个 User 类型的值或者指针。 //在这个例子中当我们使用指针时,Go 调整和解引用指针使得调用可以被执行。注意,当接受者不是一个指针时,该方法操作对应接受者的值的副本(意思就是即使你使用了指针调用函数,但是函数的接受者是值类型,所以函数内部操作还是对副本的操作,而不是指针操作。 //我们修改 Notify 方法,让它的接受者使用指针类型: func (u *User) Notify() { fmt.Printf("%v : %v \n", u.Name, u.Email) } ``` ## 匿名字段 - Golang匿名字段 :可以像字段成员那样访问匿名字段方法,编译器负责查找。 - 通过匿名字段,可获得和继承类似的复用能力。依据编译器查找次序,只需在外层定义同名方法,就可以实现 "override"。 ## 方法集 Golang方法集 :每个类型都有与之关联的方法集,这会影响到接口实现规则。 用实例 value 和 pointer 调用方法 (含匿名字段) 不受方法集约束,编译器总是查找全部方法,并自动转换 receiver 实参。 类型 T 方法集包含全部 receiver T 方法。 类型 *T 方法集包含全部 receiver T + *T 方法。 如类型 S 包含匿名字段 T,则 S 和 *S 方法集包含 T 方法。 如类型 S 包含匿名字段 *T,则 S 和 *S 方法集包含 T + *T 方法。 不管嵌入 T 或 *T,*S 方法集总是包含 T + *T 方法。 - 类型 T 方法集包含全部 receiver T 方法 ```go type T struct { int } func (t T) test() { fmt.Println("类型 T 方法集包含全部 receiver T 方法。") } func main() { t1 := T{1} fmt.Printf("t1 is : %v\n", t1) t1.test() } 输出结果: t1 is : {1} 类型 T 方法集包含全部 receiver T 方法。 ``` - 类型 *T 方法集包含全部 receiver T + *T 方法。 ```go type T struct { int } func (t T) testT() { fmt.Println("类型 *T 方法集包含全部 receiver T 方法。") } func (t *T) testP() { fmt.Println("类型 *T 方法集包含全部 receiver *T 方法。") } func main() { t1 := T{1} t2 := &t1 fmt.Printf("t2 is : %v\n", t2) t2.testT() t2.testP() } 输出结果: t2 is : &{1} 类型 *T 方法集包含全部 receiver T 方法。 类型 *T 方法集包含全部 receiver *T 方法。 ``` - 给定一个结构体类型 S 和一个命名为 T 的类型,方法提升像下面规定的这样被包含在结构体方法集中: 如类型 S 包含匿名字段 T,则 S 和 *S 方法集包含 T 方法。 这条规则说的是当我们嵌入一个类型,嵌入类型的接受者为值类型的方法将被提升,可以被外部类型的值和指针调用。 ```go type S struct { T } type T struct { int } func (t T) testT() { fmt.Println("如类型 S 包含匿名字段 T,则 S 和 *S 方法集包含 T 方法。") } func main() { s1 := S{T{1}} s2 := &s1 fmt.Printf("s1 is : %v\n", s1) s1.testT() fmt.Printf("s2 is : %v\n", s2) s2.testT() } 输出结果: s1 is : {{1}} 如类型 S 包含匿名字段 T,则 S 和 *S 方法集包含 T 方法。 s2 is : &{{1}} 如类型 S 包含匿名字段 T,则 S 和 *S 方法集包含 T 方法。 ``` - 如类型 S 包含匿名字段 *T,则 S 和 *S 方法集包含 T + *T 方法。 这条规则说的是当我们嵌入一个类型的指针,嵌入类型的接受者为值类型或指针类型的方法将被提升,可以被外部类型的值或者指针调用。 ```go type S struct { T } type T struct { int } func (t T) testT() { fmt.Println("如类型 S 包含匿名字段 *T,则 S 和 *S 方法集包含 T 方法") } func (t *T) testP() { fmt.Println("如类型 S 包含匿名字段 *T,则 S 和 *S 方法集包含 *T 方法") } func main() { s1 := S{T{1}} s2 := &s1 fmt.Printf("s1 is : %v\n", s1) s1.testT() s1.testP() fmt.Printf("s2 is : %v\n", s2) s2.testT() s2.testP() } 输出结果: s1 is : {{1}} 如类型 S 包含匿名字段 *T,则 S 和 *S 方法集包含 T 方法 如类型 S 包含匿名字段 *T,则 S 和 *S 方法集包含 *T 方法 s2 is : &{{1}} 如类型 S 包含匿名字段 *T,则 S 和 *S 方法集包含 T 方法 如类型 S 包含匿名字段 *T,则 S 和 *S 方法集包含 *T 方法 ``` ## 表达式 根据调用者不同,方法分为两种表现形式: ```go instance.method(args...) ---> <type>.func(instance, args...) ``` 前者称为 method value,后者 method expression。 两者都可像普通函数那样赋值和传参,区别在于 method value 绑定实例,而 method expression 则须显式传参。 需要注意,method value 会复制 receiver。 ```go type User struct { id int name string } func (self *User) Test() { fmt.Printf("%p, %v\n", self, self) } func main() { u := User{1, "Tom"} u.Test() mValue := u.Test mValue() // 隐式传递 receiver mExpression := (*User).Test mExpression(&u) // 显式传递 receiver } ``` ```go type User struct { id int name string } func (self *User) TestPointer() { fmt.Printf("TestPointer: %p, %v\n", self, self) } func (self User) TestValue() { fmt.Printf("TestValue: %p, %v\n", &self, self) } func main() { u := User{1, "Tom"} fmt.Printf("User: %p, %v\n", &u, u) mv := User.TestValue mv(u) mp := (*User).TestPointer mp(&u) mp2 := (*User).TestValue // *User 方法集包含 TestValue。签名变为 func TestValue(self *User)。实际依然是 receiver value copy。 mp2(&u) } ```
顶部
收展
底部
[TOC]
目录
Go语言 函数
Go语言 方法
Go语言 延迟调用(defer)
Go语言 异常处理
相关推荐
Go基础
Go数据类型
Go面向对象
Go并发编程
Go数据操作