文档章节

Golang interface接口全面理解(二)

90design
 90design
发布于 03/12 15:57
字数 823
阅读 291
收藏 6
点赞 0
评论 2

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
粉丝 11
博文 43
码字总数 31878
作品 0
潍坊
程序员
加载中

评论(2)

90design
90design

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

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

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

xumaojun ⋅ 03/12 ⋅ 0

Golang 中的接口 (interface)

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

hww_面条酱 ⋅ 2017/11/01 ⋅ 0

以io.Writer为例看go中的interface{}

阅读[该文][1]后的一些理解 1 io.Writer接口 [io.Writer][2]接口有如下定义 2 somepkg.abc类型实现了io.Writer接口 3 io.Writer的应用 通常,我们在使用fmt包的时候是使用[Println][7]/[Pri...

waynehu ⋅ 2013/05/07 ⋅ 0

在 Golang 中用名字调用函数

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

kuerant ⋅ 2014/01/26 ⋅ 0

关于go接口的一些说明

什么是接口 接口是golang最重要的特性之一,在Go中,接口interface其实和其他语言的接口意思没什么区别。interface理解其为一种类型的规范或者约定。一种类型是不是“实现”了一个接口呢?就...

壬癸甲乙 ⋅ 2013/08/30 ⋅ 0

golang: 类型转换和类型断言

类型转换在程序设计中都是不可避免的问题。当然有一些语言将这个过程给模糊了,大多数时候开发者并不需要去关注这方面的问题。但是golang中的类型匹配是很严格的,不同的类型之间通常需要手动...

陈亦 ⋅ 2014/01/20 ⋅ 8

Golang 全面深入系列之 Error

What you are wasting today is tomorrow for those who died yesterday; what you hate now is the future you can not go back. 你所浪费的今天是昨天死去的人奢望的明天; 你所厌恶的现在......

xjtuhit ⋅ 03/20 ⋅ 0

golang: 详解interface和nil

golang的nil在概念上和其它语言的null、None、nil、NULL一样,都指代零值或空值。nil是预先说明的标识符,也即通常意义上的关键字。在golang中,nil只能赋值给指针、channel、func、interfa...

陈亦 ⋅ 2014/01/19 ⋅ 28

golang之旅--接口 (interface)

golang接口简介 go语言不是传统的面向对象语言,因此没有类和继承的概念。 go语言中的接口跟java中的接口有点类似,接口可以有多个实现。 go语言的接口是go的一种类型,用来指定一组方法(方法...

花_现 ⋅ 2016/12/05 ⋅ 3

golang入门学习笔记(二)

作者: 一字马胡 转载标志 【2017-11-22】 更新日志 日期 更新内容 备注 2017-11-22 新建文章 go语言入门学习笔记(二) golang入门学习笔记系列 golang入门学习笔记(一) interface for go...

一字马胡 ⋅ 2017/11/22 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

vim基础-编辑模式-命令模式

编辑模式:可以编辑修改文件。编辑模式下 按“esc”键返回一般模式。 按一次“Insert”键 (一般在键盘回格键右边)作用和“i”一样表示“插入”。按两次“Insert”键表示“替换”,作用为:...

ZHENG-JY ⋅ 18分钟前 ⋅ 0

MaxCompute读取分析OSS非结构化数据的实践经验总结

摘要: 本文背景 很多行业的信息系统中,例如金融行业的信息系统,相当多的数据交互工作是通过传统的文本文件进行交互的。此外,很多系统的业务日志和系统日志由于各种原因并没有进入ELK之类...

阿里云云栖社区 ⋅ 22分钟前 ⋅ 0

Linux操作系统有何优势?Linux学习

  当今世界流行的操作系统有3大类,Linux、Mac OS和Windows操作系统,Linux操作系统因其开源、免费、跨平台、良好的界面等特性,深受广大程序员们的青睐!   Linux操作系统被广泛的应用于...

老男孩Linux培训 ⋅ 24分钟前 ⋅ 0

Spring Cloud Spring Boot mybatis分布式微服务云架构 开发Web应用

静态资源访问 在我们开发Web应用的时候,需要引用大量的js、css、图片等静态资源。 默认配置 Spring Boot默认提供静态资源目录位置需置于classpath下,目录名需符合如下规则: /static /pub...

itcloud ⋅ 28分钟前 ⋅ 0

6月19日任务 设置更改root密码、连接mysql、mysql常用命令

13.1 设置更改root密码 1. /usr/local/mysql/bin/mysql -uroot 设置环境变量 : export PATH=$PATH:/usr/local/mysql/bin/ 永久生效: vim /etc/profile 加入 export PATH=$PATH:/usr/local/m......

吕湘颖 ⋅ 30分钟前 ⋅ 0

MaxCompute读取分析OSS非结构化数据的实践经验总结

摘要: 本文背景 很多行业的信息系统中,例如金融行业的信息系统,相当多的数据交互工作是通过传统的文本文件进行交互的。此外,很多系统的业务日志和系统日志由于各种原因并没有进入ELK之类...

猫耳m ⋅ 31分钟前 ⋅ 0

Spring MVC controller,return重定向redirect:

@RequestMapping(value="/save",method=RequestMethod.POST)public String doSave(Course course) {log.debug("Info of Course");log.debug(ReflectionToStringBuilder.toStr......

颖伙虫 ⋅ 38分钟前 ⋅ 0

JavaSE——线程介绍

声明:本栏目所使用的素材都是凯哥学堂VIP学员所写,学员有权匿名,对文章有最终解释权;凯哥学堂旨在促进VIP学员互相学习的基础上公开笔记。 线程: 介绍:管线程叫多任务处理,首先你得知道...

凯哥学堂 ⋅ 42分钟前 ⋅ 0

ORM——使用spring jpa data实现逻辑删除

前言 在业务中是忌讳物理删除数据的,数据的这个对于一个IT公司可以说是最核心的资产,如果删除直接就物理删除,无疑是对核心资产的不重视,可能扯的比较远,本文最主要是想通过spring jpa ...

alexzhu592 ⋅ 48分钟前 ⋅ 0

CDN caching

Incapsula应用感知CDN使用智能分析和频率分析来动态缓存内容,并最大限度地提高效率。确保可直接从RAM获取最常访问的资源,而不依赖于较慢的访问机制。 1、 静态内容缓存 Incapsula缓存静态内...

上树的熊 ⋅ 51分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部