Golang教程:(十九)接口 - II
2018-02-06 16:13
441 查看
欢迎来到Golang系列教程的第十九篇。这是介绍接口的第二篇。
在接口I中所有例子都是以值为接收者。也可以使用指针接收者来实现接口。让我们通过一个程序看看这是如何做到的。
在 Playground 中运行
在上面的程序中,第13行,
如果将第42行的注释去掉,我们将得到一个编译错误:
45 行是合法的,因为我们将指向
程序剩下的部分不言自明。程序的输出如下:
一个类型可以实现多个接口。让我们通过下面的程序看看这是如何做到的。
在 Playground 中运行
上面的程序在第7行和第11行分别声明了两个接口
结构体
在第41行我们将
程序的输出为:
虽然Go没有提供继承机制,但是仍然可以通过嵌入其他接口的方式创建一个新的接口。
下面的程序说明了这一点。
在 Playground 中运行
在上面的程序第15行,通过嵌入
任何一个实现了
在第46行,
程序的输出为:
接口的 0 值是 nil。一个 nil 接口的底层类型和值都是 nil。
在 Playground 中运行
上面的程序中,
如果我们试图在一个
在 Playground 中运行
上面的程序中,因为
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0xffffffff addr=0x0 pc=0xc8527]
用指针接收者实现接口
在接口I中所有例子都是以值为接收者。也可以使用指针接收者来实现接口。让我们通过一个程序看看这是如何做到的。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 p := Person{"Sam", 25} d1 = p 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 ap := &a d2 = ap //This works since Describer interface //is implemented by Address pointer in line 22 d2.Describe() }
在 Playground 中运行
在上面的程序中,第13行,
Person结构体以值作为接收者实现了
Describer接口,而在第22行,
Address结构体以指针作为接收者实现了
Describer接口。
如果将第42行的注释去掉,我们将得到一个编译错误:
main.go:42: cannot use a (type Address) as type Describer in assignment: Address does not implement Describer (Describe method has pointer receiver)。这是因为,在第22行我们使用的是
Address指针作为接收者来实现
Describer接口,但是我们试图将一个没有实现
Describer的接口的值类型的变量
a赋值给接口变量
d2。第
45 行是合法的,因为我们将指向
a的指针
ap赋值给
d2。
程序剩下的部分不言自明。程序的输出如下:
Sam is 25 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()) }
在 Playground 中运行
上面的程序在第7行和第11行分别声明了两个接口
SalaryCalculator和
LeaveCalculator。
结构体
Employee(定义在第15行)在第24行实现了
SalaryCalculator接口的
DisplaySalary方法,而在第28行实现了
LeaveCalculator接口的
CalculateLeavesLeft方法。现在
Employee同时实现了
SalaryCalculator和
LeaveCalculator两个接口。
在第41行我们将
e赋值给
SalaryCalculator类型的变量,在第43行我们将同样的变量
e赋值给了
LeaveCalculator类型的变量。这是合法的,因为
e的类型是
Employee,而
Employee实现了
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()) }
在 Playground 中运行
在上面的程序第15行,通过嵌入
SalaryCalculator和
LeaveCalculator两个接口的方式创建了新的接口
EmployeeOperations。
任何一个实现了
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
接口的0值
接口的 0 值是 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) } }
在 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() }
在 Playground 中运行
上面的程序中,因为
d1是 nil。程序将在运行时触发 panic:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0xffffffff addr=0x0 pc=0xc8527]
相关文章推荐
- Golang教程:(十九)接口 - II
- Golang初级系列教程-接口
- PHP类实例教程(十九):PHP类接口的定义与规范
- Golang初级系列教程-接口2
- Golang教程:(十八)接口 - I
- Golang教程:(十八)接口 - I
- Golang初级系列教程-接口多态性
- java 服务器接口快速开发之servlet详细教程
- 【工业串口和网络软件通讯平台(SuperIO)教程】九.重写通讯接口函数,实现特殊通讯方式
- 使用golang做http接口压力测试并输出到echarts散点图中
- Golang教程:(二)Hello World
- Golang教程:(七)包
- GObject 参考手册:教程:如何定义和实现接口
- Unity3D Shader官方教程翻译(十九)----Shader语法,编写表面着色器
- 基于C#的接口基础教程
- golang 接口interface{}、断言、switch type
- 关于golang处理PHP接口BOM头问题
- C#调用webservice接口的最新方法教程
- vs2005视频教程 之 抽象类和接口 二 [视频]
- 淘宝API学习之道:淘宝TOP之API接口接入教程