「译」 part 19: golang 接口 2 golang接口测试框架
yuyutoo 2024-10-11 21:41 15 浏览 0 评论
[译] part 19: golang 接口 2
- 原文地址:Part 19: Interfaces - II
- 原文作者:Naveen R
- 译者:咔叽咔叽 转载请注明出处。
指针接收者的接口 VS 值接收者的接口
我们在上一篇文章中讨论的所有示例接口都是使用值接收者实现的。也可以使用指针接收者实现接口。在使用指针接收者实现接口时需要注意一些细微之处。让我们使用以下程序了解一下。
package main import "fmt" type Describer interface { Describe() } type Person struct { name string age int } func (p Person) Describe() { //implemented using value receiver fmt.Printf("%s is %d years old\n", p.name, p.age) } type Address struct { state string country string } func (a *Address) Describe() { //implemented using pointer receiver fmt.Printf("State %s Country %s", a.state, a.country) } func main() { var d1 Describer p1 := Person{"Sam", 25} d1 = p1 d1.Describe() p2 := Person{"James", 32} d1 = &p2 d1.Describe() var d2 Describer a := Address{"Washington", "USA"} /* compilation error if the following line is uncommented cannot use a (type Address) as type Describer in assignment: Address does not implement Describer (Describe method has pointer receiver) */ //d2 = a d2 = &a //This works since Describer interface //is implemented by Address pointer in line 22 d2.Describe() } 复制代码
Run in playground
在上面的程序中的第 13 行,Person结构使用值接收者实现了Describer接口。
正如我们之前已经学过和讨论的方法那样,带有值接收者的方法同时接受指针和值接收者。用值或者值的解引用去调用值方法是合法的。
p1是Person类型的值,它在第 29 行中赋值给d1。Person实现了d1接口,因此 30 行,将打印Sam is 25 years old.
类似地,在第 32 行中将&p2赋值给d1。 因此第 33 行将打印James is 32 years old.,太棒了:)。
在第 22 行,Address结构使用指针接收者实现Describer接口。 如果上面程序的第 45 行没有被取消注释,我们将看到编译错误main.go:42: cannot use a (type Address) as type Describer in assignment: Address does not implement Describer (Describe method has pointer receiver)。这是因为,Describer接口是使用第地址指针接收者实现的,我们尝试分配一个值类型a,但它没有实现Describer接口。这肯定会让你感到惊讶,因为我们之前已经知道带有指针接收者的方法将同时接受指针和值接收者。那么第 45 行的代码为什么不行呢?
原因是在任何已经是指针或可以寻址的任何类型上调用指针值方法是合法的。而存储在接口中的具体值是不可寻址的,因此编译器不可能自动获取第 45 行a的地址,因此这段代码失败了。
第 47 行是正确的,因为我们将a的地址&a赋值给了d2。
该程序的其余部分是通俗易懂的。该程序将打印,
Sam is 25 years old James is 32 years old State Washington Country USA 复制代码
实现多个接口
一个类型可以实现多个接口。让我们看看如何在以下程序中完成此操作。
package main import ( "fmt" ) type SalaryCalculator interface { DisplaySalary() } type LeaveCalculator interface { CalculateLeavesLeft() int } type Employee struct { firstName string lastName string basicPay int pf int totalLeaves int leavesTaken int } func (e Employee) DisplaySalary() { fmt.Printf("%s %s has salary $%d", e.firstName, e.lastName, (e.basicPay + e.pf)) } func (e Employee) CalculateLeavesLeft() int { return e.totalLeaves - e.leavesTaken } func main() { e := Employee { firstName: "Naveen", lastName: "Ramanathan", basicPay: 5000, pf: 200, totalLeaves: 30, leavesTaken: 5, } var s SalaryCalculator = e s.DisplaySalary() var l LeaveCalculator = e fmt.Println("\nLeaves left =", l.CalculateLeavesLeft()) } 复制代码
Run in playground
上面程序在第 7 行和第 11 行分别声明了两个接口SalaryCalculator和LeaveCalculator。
在第 15 行中定义的Employee结构,实现了SalaryCalculator接口的DisplaySalary方法和LeaveCalculator接口的CalculateLeavesLeft方法。现在,Employee实现了SalaryCalculator和LeaveCalculator接口。
在第 41 行,我们将e赋值给SalaryCalculator接口类型的变量。在第 43 行,我们将相同的变量e分配给LeaveCalculator接口类型的变量。这就使得Employee类型的变量e实现了SalaryCalculator和LeaveCalculator接口。
程序输出,
Naveen Ramanathan has salary $5200 Leaves left = 25 复制代码
接口的嵌入
尽管 go 不提供继承,但可以通过嵌入其他接口来创建新接口。
我们来看看是怎么完成的。
package main import ( "fmt" ) type SalaryCalculator interface { DisplaySalary() } type LeaveCalculator interface { CalculateLeavesLeft() int } type EmployeeOperations interface { SalaryCalculator LeaveCalculator } type Employee struct { firstName string lastName string basicPay int pf int totalLeaves int leavesTaken int } func (e Employee) DisplaySalary() { fmt.Printf("%s %s has salary $%d", e.firstName, e.lastName, (e.basicPay + e.pf)) } func (e Employee) CalculateLeavesLeft() int { return e.totalLeaves - e.leavesTaken } func main() { e := Employee { firstName: "Naveen", lastName: "Ramanathan", basicPay: 5000, pf: 200, totalLeaves: 30, leavesTaken: 5, } var empOp EmployeeOperations = e empOp.DisplaySalary() fmt.Println("\nLeaves left =", empOp.CalculateLeavesLeft()) } 复制代码
Run in playground
上面程序的第 15 行中的EmployeeOperations接口是通过嵌入SalaryCalculator和LeaveCalculator接口创建的。
如果一个类型提供了SalaryCalculator和LeaveCalculator接口中存在的方法的方法定义,就可以说实现了EmployeeOperations接口。
Employee结构实现了EmployeeOperations接口,因为它分别在第 29 行和第 33 行中的DisplaySalary和CalculateLeavesLeft方法提供了定义。
在第 46 行,类型为Employee的e被赋值给EmployeeOperations类型的empOp。在接下来的两行中,在empOp上调用DisplaySalary()和CalculateLeavesLeft()方法。
程序输出,
Naveen Ramanathan has salary $5200 Leaves left = 25 复制代码
接口的零值
接口的零值是nil。 nil接口的值和类型都为nil。
package main import "fmt" type Describer interface { Describe() } func main() { var d1 Describer if d1 == nil { fmt.Printf("d1 is nil and has type %T value %v\n", d1, d1) } } 复制代码
Run in playground
上述程序中的d1为nil,此程序将输出
d1 is nil and has type <nil> value <nil> 复制代码
如果我们尝试在nil接口上调用方法,程序将会发生panic,因为nil接口既没有具体值也没有具体类型。
package main type Describer interface { Describe() } func main() { var d1 Describer d1.Describe() } 复制代码
Run in playground
由于上面程序中的d1是nil,因此程序将会出现panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0xffffffff addr=0x0 pc=0xc8527]"
相关推荐
- 《保卫萝卜2》安卓版大更新 壕礼助阵世界杯
-
《保卫萝卜2:极地冒险》本周不仅迎来了安卓版本的重大更新,同时将于7月4日本周五,带来“保卫萝卜2”安卓版本世界杯主题活动的火热开启,游戏更新与活动两不误。一定有玩家会问,激萌塔防到底进行了哪些更新?...
- 儿童手工折纸:胡萝卜,和孩子一起边玩边学carrot
-
1、准备两张正方形纸,一橙一绿,对折出折痕。2、橙色沿其中一条对角线如图折两三角形。3、把上面三角折平,如图。4、绿色纸折成三角形。5、再折成更小的三角形。6、再折三分之一如图。7、打开折纸,压平中间...
- 《饥荒》食物代码有哪些(饥荒最新版代码总汇食物篇)
-
饥荒游戏中,玩家们需要获取各种素材与食物,进行生存。玩家们在游戏中,进入游戏后按“~”键调出控制台使用代码,可以直接获得素材。比如胡萝卜的代码是carrot,玉米的代码是corn,南瓜的代码是pump...
- Skyscanner:帮你找到最便宜机票 订票不求人
-
你喜欢旅行吗?在合适的时间、合适的目的地,来一场说走就走的旅行?机票就是关键!Skyscanner这款免费的手机应用,在几秒钟内比较全球600多家航空公司的航班安排、价格和时刻表,帮你节省金钱和时间。...
- 小猪佩奇第二季50(小猪佩奇第二季英文版免费观看)
-
Sleepover过夜Itisnighttime.现在是晚上。...
- 我在民政局工作的那些事儿(二)(我在民政局上班)
-
时间到了1997年的秋天,经过一年多的学习和实践,我在处理结婚和离婚的事情更加的娴熟,也获得了领导的器重,所以我在处理平时的工作时也能得心应手。这一天我正在离婚处和同事闲聊,因为离婚处几天也遇不到人,...
- 夏天来了就你还没瘦?教你不节食13天瘦10斤的哥本哈根减肥法……
-
好看的人都关注江苏气象啦夏天很快就要来了你是否和苏苏一样身上的肉肉还没做好准备?真是一个悲伤的故事……下面这个哥本哈根减肥法苏苏的同事亲测有效不节食不运动不反弹大家快来一起试试看吧~DAY1...
- Pursuing global modernization for peaceful development, mutually beneficial cooperation, prosperity for all
-
AlocalworkeroperatesequipmentintheChina-EgyptTEDASuezEconomicandTradeCooperationZonei...
- Centuries-old tea road regains glory as Belt and Road cooperation deepens
-
FUZHOU/ST.PETERSBURG,Oct.2(Xinhua)--NestledinthepicturesqueWuyiMountainsinsoutheastChi...
- Ftrace function graph简介(flat function)
-
引言由于android开发的需要与systrace的普及,现在大家在进行性能与功耗分析时候,经常会用到systrace跟pefetto.而systrace就是基于内核的eventtracing来实...
- JAVA历史版本(java各版本)
-
JAVA发展1.1996年1月23日JDK1.0Java虚拟机SunClassicVM,Applet,AWT2.1997年2月19日JDK1.1JAR文件格式,JDBC,JavaBea...
- java 进化史1(java的进阶之路)
-
java从1996年1月第一个版本诞生,到2022年3月最新的java18,已经经历了27年,整整18个大的版本。很久之前有人就说java要被淘汰,但是java活到现在依然坚挺,不知道java还能活...
- 学习java第二天(java学完后能做什么)
-
#java知识#...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- 《保卫萝卜2》安卓版大更新 壕礼助阵世界杯
- 儿童手工折纸:胡萝卜,和孩子一起边玩边学carrot
- 《饥荒》食物代码有哪些(饥荒最新版代码总汇食物篇)
- Skyscanner:帮你找到最便宜机票 订票不求人
- 小猪佩奇第二季50(小猪佩奇第二季英文版免费观看)
- 我在民政局工作的那些事儿(二)(我在民政局上班)
- 夏天来了就你还没瘦?教你不节食13天瘦10斤的哥本哈根减肥法……
- Pursuing global modernization for peaceful development, mutually beneficial cooperation, prosperity for all
- Centuries-old tea road regains glory as Belt and Road cooperation deepens
- 15 THE NUTCRACKERS OF NUTCRACKER LODGE (CONTINUED)胡桃夹子小屋里的胡桃夹子(续篇)
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)