第 12 章 方法
方法 其实就是一个函数,在 func
这个关键字和方法名中间加入了一个特殊的接收器类型。接收器可以是结构体类型或者是非结构体类型。接收器是可以在方法的内部访问的。
1 2
| func (t Type) methodName(parameterList) returnList{ }
|
上面的代码片段创建了一个接收器类型为 Type
的方法 methodName
。
12.1 实例绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package main
import "fmt"
type Lesson struct { Name string Target string }
func (lesson Lesson) PrintInfo() { fmt.Println("name:", lesson.Name) fmt.Println("target:", lesson.Target) }
func main() { l := Lesson.Lesson{ Name: "从0到Go语言微服务架构师", Target: "全面掌握Go语言微服务落地,代码级一次性解决微服务和分布式系统。", } l.PrintInfo() }
|
上面的程序中定义了一个与结构体 Lesson
绑定的方法 PrintInfo()
,其中 PrintInfo
是方法名, (lesson Lesson)
表示将此方法与 Lesson
的实例绑定,这里我们把 Lesson
称为方法的接收者,而 lesson
表示实例本身,相当于 Python 中的 self
,Java 中的 this
。
当然,你可以把上面程序的方法改成一个函数,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package main
import "fmt"
type Lesson struct { Name string Target string }
func PrintInfo(lesson Lesson) { fmt.Println("name:", lesson.Name) fmt.Println("target:", lesson.Target) }
func main() { lesson := Lesson{ Name: "从0到Go语言微服务架构师", Target: "全面掌握Go语言微服务落地,代码级一次性解决微服务和分布式系统。", } PrintInfo(lesson) }
|
运行这个程序,也同样会输出上面一样的答案,那么我们为什么还要用方法呢?因为在 Go 中,相同的名字的方法可以定义在不同的类型上,而相同名字的函数是不被允许的。如果你在上面这个程序添加一个同名函数,就会报错。但是在不同的结构体上面定义同名的方法就是可行的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package main
import "fmt"
type Lesson struct { Name string Target string }
func (lesson Lesson) PrintInfo() { fmt.Println("Lesson name:", lesson.Name) fmt.Println("Lesson target:", lesson.Target) }
type Author struct { Name string }
func (author Author) PrintInfo() { fmt.Println("author name:", author.name) }
func main() { lesson := Lesson{ Name: "从0到Go语言微服务架构师", Target: "全面掌握Go语言微服务落地,代码级一次性解决微服务和分布式系统。", } lesson.PrintInfo() author := Author{"欢喜"} author.PrintInfo() }
|
12.2 指针接收器与值接收器
值接收器和指针接收器之间的区别在于,在指针接收器的方法内部的改变对于调用者是可见的,然而值接收器的方法内部的改变对于调用者是不可见的,所以若要改变实例的属性时,必须使用指针作为方法的接收者。看看下面的例子就知道了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| package main
import "fmt"
type Lesson struct { Name string Target string SpendTime int }
func (lesson Lesson) PrintInfo() { fmt.Println("name:", lesson.Name) fmt.Println("target:", lesson.Target) fmt.Println("spendTime:", lesson.SpendTime) }
func (lesson Lesson) ChangeLessonName(name string) { lesson.name = name }
func (lesson *Lesson) AddSpendTime(n int) { lesson.SpendTime = lesson.SpendTime + n }
func main() { lesson := Lesson{ Name: "从0到Go语言微服务架构师", Target: "全面掌握Go语言微服务落地,代码级一次性解决微服务和分布式系统。", PrintTimes: 1, } fmt.Println("before change") lesson.PrintInfo()
fmt.Println("after change") lesson.AddSpendTime(2) lesson.ChangeLessonName("Go语言微服务架构核心22讲") lesson.PrintInfo() }
|
在上面的程序中, AddSpendTime
使用指针接收器最终能改变实例的 SpendTime
值,然而使用值接收器的 ChangeLessonName
最终没有改变实例 Name
的值。
12.3 在方法中使用值接收器 与 在函数中使用值参数
当一个函数有一个值参数,它只能接受一个值参数。当一个方法有一个值接收器,它可以接受值接收器和指针接收器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package main
import "fmt"
type Lesson struct { Name string Target string PrintTimes int }
func (lesson Lesson) PrintInfo() { fmt.Println(lesson.Name) }
func PrintInfo(lesson Lesson) { fmt.Println(lesson.name) }
func main() { lesson := Lesson{"Go语言微服务核心架构22讲"} PrintInfo(lesson) lesson.PrintInfo()
bPtr := &lesson bPtr.PrintInfo() }
|
在上面的程序中,使用值参数 PrintInfo(lesson)
来调用这个函数是合法的,使用值接收器来调用 lesson.PrintInfo()
也是合法的。
然后在程序中我们创建了一个指向 Lesson
的指针 bPtr
,通过使用指针接收器来调用 bPtr.PrintInfo()
是合法的,但使用值参数调用 PrintInfo(bPtr)
是非法的。
12.4 在非结构体上的方法
不仅可以在结构体类型上定义方法,也可以在非结构体类型上定义方法,但是有一个问题。为了在一个类型上定义一个方法,方法的接收器类型定义和方法的定义应该在同一个包中。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package main
import "fmt"
type myInt int
func (a myInt) add(b myInt) myInt { return a + b }
func main() { var x myInt = 50 var y myInt = 7 fmt.Println(x.add(y)) }
|
如何学习Go语言微服务,快速步入架构师
添加微信 |
公众号更多内容 |
 |
 |