文档章节

Golang interface接口全面理解(二)

90design
 90design
发布于 03/12 15:57
字数 823
阅读 511
收藏 6

Now your life, life in the future to play you, now do not work hard, the future suck.

现在不玩命,将来命玩你,现在不努力,未来不给力。

 指针 vs 值类型实现接口

我们在第1部分中讨论的所有示例接口都是使用值receivers 实现的。也可以使用指针receivers 来实现接口。在使用指针receivers 实现接口时需要注意的细微之处。让我们了解使用下面的程序。

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"}

	//d2 = a  // 不能使用值类型(编译失败)①

	d2 = &a 
	d2.Describe()
    a.Describe()  // 直接使用值类型调用②

}

为什么上面d2 = a处会引发panic( 此处不是panic, 而是引发编译错误。 

cannot use a (type Address) as type Describer  in assignment: Address does not implement        Describer (Describe method has pointer receiver), 感谢码友@神州浪子的指正):

.\interface1.go:39:5: cannot use a (type Address) as type Describer in assignment:
	Address does not implement Describer (Describe method has pointer receiver)

而a.Describe() 不会引起编译失败???

原因是: 任何指针变量或者可以获取指针的变量调用指针方法都是合法的。但是存储在接口中的值是无法寻址的,因此编译器无法自动获取指针地址引发panic.

或者说: d2 = a 此行报错, 简单地说,就是传过去(赋值)的对象必须实现了接口要求的方法, a并没有实现Describe()方法,a的指针实现了Describe()方法。

 

实现多个接口

一个类型可以实现多个接口。让我们看看这是如何在下面的程序中完成的。

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())
}

 

接口的嵌套

虽然go不提供类似JAVA的继承,但可以通过嵌入其他接口来创建新的接口。

让我们看看这是如何完成的:

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())
	
	//当然更是实现了两个子接口
	var lc SalaryCalculator = e
	lc.DisplaySalary()
}

 

接口零值

一个接口的零值是nil , 也有其nil的类型。

package main

import "fmt"

type Describer interface {  
    Describe()
}

func main() {  
    var d1 Describer
    if d1 == nil {
        fmt.Printf("d1 is nil and 类型 %T 值%v\n", d1, d1)
    }
}

如果我们使用nil的接口调用一个方法,则程序会panic,因为nil interface既没有底层的值也没有对应的具体类型。或者说像JAVA的空指针异常!

 

The End!

 

 

 

 

© 著作权归作者所有

共有 人打赏支持
90design
粉丝 16
博文 53
码字总数 38247
作品 0
潍坊
程序员
私信 提问
加载中

评论(2)

90design
90design

引用来自“神州浪子”的评论

纠正一处文中的错误:那不叫panic,那叫编译不通过。
感谢指正!已改正
神州浪子
神州浪子
纠正一处文中的错误:那不叫panic,那叫编译不通过。
Go语言学习笔记(四)结构体struct & 接口Interface & 反射reflect

加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 结构体struct struct 用来自定义复杂数据结构,可以包含多个字段(属性),可以嵌套; go中的struct类型理解为类,可以定义...

xumaojun
03/12
0
0
Golang 中的接口 (interface)

依赖于接口而不是实现,优先使用组合而不是继承,这是程序抽象的基本原则。Golang 中的 让编码更灵活、易扩展,使得 Go 拥有了面向对象多态的特性。在此我们记住三点就够了: 方法声明的集合...

hww_面条酱
2017/11/01
0
0
Golang的反射reflect深入理解和示例

作者:豆瓣奶茶 链接:https://www.jianshu.com/p/b46b1ccd2757 來源:简书 编程语言中反射的概念 在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用...

Golang语言社区
10/15
0
0
Golang interface接口全面理解(一)

There are three kinds of time: the future is late, and now it is flying like an arrow. The past will never stand still. 时间的步伐有三种:未来姗姗来迟,现在像箭一般飞逝,过去永远......

90design
03/12
0
3
在 Golang 中用名字调用函数

上个星期,我写了篇《Function call by name in Golang》。由于是英文的,所以被人诟病(说谁,谁知道!)。好吧,现在用中文重新写一遍。 Golang 中的函数跟 C 的一样,是个代码块,不过它可...

kuerant
2014/01/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Qt那些事0.0.15

以下与Q_DECLARE_METATYPE相关内容全部是翻译自Qt文档。参看QVariant Class | Qt Core 5.9以及QMetaType Class | Qt Core 5.9 QVariant QVariant::fromValue(const T& value) 返回一份包含v......

Ev4n
5分钟前
1
0
spring上传文件返回绝对路径,简单工具类

import com.google.common.io.Files;import lombok.extern.slf4j.Slf4j;import org.springframework.web.multipart.MultipartFile;import java.io.File;import java.io.IOExceptio......

Boss-x
17分钟前
1
0
1个开发如何撑起一个过亿用户的小程序

本文由云+社区发表 2018年12月,腾讯相册累计用户量突破1亿,月活1200万,阿拉丁指数排行 Top 30,已经成为小程序生态的重量级玩家。 三个多月来,腾讯相册围绕【在微信分享相册照片】这一核...

腾讯云加社区
23分钟前
6
0
golang ssh包使用方法介绍

在使用gexpect包发现很多问题之外,这里又尝试使用ssh user@127.0.0.1的思路进行用户切换。这里记录下具体的使用方法,遇到的ssh: must specify HostKeyCallback 问题的解法方法及最终使用过...

linuxprobe16
28分钟前
0
0
layer

Layui Layer在open弹出层中异步加载数据和form表单radio、checkbox、select不渲染,不可点击的解决办法 layer 实现弹窗提交信息 function confirmUpdateAward(i) { layer.open({ ...

mickelfeng
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部