[Go]接口的运用
在Go语言中,不能通过调用new函数或make函数创建初一个接口类型的值,也无法用字面量来表示一个接口类型的值。可以通过关键字type和interface声明接口类型,接口类型的类型字面量与结构体类型有些相似,不过结构体类型包裹的是它的字段声明,而接口类型包裹的是它的方法定义。
接口类型声明中的这些方法所代表的就是该接口的方法集合,一个接口的方法集合就是它的全部特征。对任何数据类型,只要它的方法集合中完全包含了一个接口的全部方法,那么它就一定是这个接口的实现类型。
type Pet interface {
SetName(name string)
Name() string
Category() string
}
这里声明了一个接口类型Pet,它包含了3个方法定义,这3个方法共同组成了接口类型Pet的方法集合,只要一个数据类型的方法集合中有这3个方法,那么它就一定是Pet接口的实现类型。这是一种无侵入式的接口实现方式。
那怎样判定一个数据类型的某个方法实现的就是某个接口类型中的某个方法呢?有两个充分必要条件:
1)两个方法的签名需要完全一致
2)两个方法的名称要一模一样
type Dog struct {
name string // 名字。
}
func (dog *Dog) SetName(name string) {
dog.name = name
}
func (dog Dog) Name() string {
return dog.name
}
func (dog Dog) Category() string {
return "dog"
}
Dog类型本身的方法集合中只包含了2个值方法,而它的指针类型*Dog方法集合却包含了3个方法(两个值方法加一个指针方法),又由于这3个方法恰恰分别是Pet接口中某个方法的实现,所以*Dog类型就成为了Pet接口的实现类型。
dog := Dog{"little pig"}
var pet Pet = &dog
因此可以声明并初始化一个Dog类型的变量dog,然后把它的指针值赋给类型为Pet的变量pet。
对于一个接口类型的变量,赋给它的值可以被叫做它的实际值,而该值的类型可以被叫做这个变量的实际类型(动态类型)
如把&dog的结果值赋给了变量pet,这个结果值就是变量pet的动态值,*Dog就是该变量的动态类型。对于变量pet来说,它的静态类型就是Pet,并且永远是Pet,但是它的动态类型会随着我们赋给它的动态值而变化,并且在给一个接口类型的变量赋予实际的值之前,它的动态类型是不存在的。
1、当为一个接口变量赋值时会发生什么?
假设把Pet接口声明简化一下
type Pet interface {
Name() string
Category() string
//去掉了SetName方法
}
这时
dog := Dog{"little pig"}var pet Pet = dog
dog.SetName("monster")
这时pet变量的字段name的值依然时”little pig“
由于dog的SetName方法时指针方法,所以该方法的持有的接收者就是指向dog的指针值的副本,因而其中对接收者的name字段的设置就是对变量dog的改动。那么当dog.SetName执行之后,dog的name字段的值就一定是”monster“。
那为什么dog的name变量,而pet却没有呢?
如果使用一个变量给另外一个变量赋值,那么真正赋给后者的,并不是前者持有的那个值,而是该值的一个副本。 例如
dog1 := Dog{"litte dog"}
dog2 := dog1
dog1.name = "monster"
此时dog2的值仍然回收”litter dog“
接口类型本身时无法被值化的,在赋予它实际的值之前,它的值一定会是nil,这是它的零值。
当给接口变量赋值时,该变量的动态类型会与它的动态值一起被存储在一个专用的数据结构中。这样的一个变量的值其实时这个专用数据结构的一个实例,而不是我们赋给该变量的那个实际的值。所以pet的值与dog值肯定是不同的,无论从它们存储的内容还是存储的结构。
Go语言把这个专用的数据结构叫做iface,iface会包含两个指针,一个时指向类型信息的指针,另一个时指向动态值的指针。这里的类型信息由另一个专用数据结构的实例承载,其中包含了动态值的类型,以及使它实现了接口的方法和调用它们的途径。
总之,接口变量被赋予动态值的时候,存储的是包含这个动态值的副本的一个结构更加复杂的值。
2、接口变量的值在什么情况下才真正为nil?
var dog1 *Dog
fmt.Println("The first dog is nil.")
dog2 := dog1
fmt.Println("The second dog is nil.")
var pet Pet = dog2
if pet == nil {
fmt.Println("The pet is nil.")
} else {
fmt.Println("The pet is not nil.")
}
dog1和dog2是nil很好理解,那pet会是nil吗?
pet的值不会是nil,因为这个动态值只是pet值的一部分。此时pet动态类型是*Dog
把nil赋值给了pet,但pet的值却不是nil,这不是很奇怪吗?
在Go语言中,把字面量nil表示的值叫做无类型的nil,这是真正的nil,因为它的类型也是nil。虽然dog2的值是真正的nil,但当我们把这个变量赋给pet的时候,Go语言会把它的类型和值放在一起考虑。即此时Go语言会识别初赋予pet的值是一个*Dog类型的nil,然后Go语言会用一个iface实例包装它,包装后的产物肯定就不是nil了。
因而只要把一个有类型的nil赋给接口变量,那这个变量的值就一定不会是真正的nil。
那要怎样才能让一个接口变量的值真正为nil呢?要么只声明它当不做初始化,要么之间把字面量nil赋给它。
3、怎样实现接口之间的组合?
接口类型间的嵌入被称为接口的组合。接口的组合不会出现屏蔽现象
type Animal interface {
// ScientificName 用于获取动物的学名。
ScientificName() string
// Category 用于获取动物的基本分类。
Category() string
}
type Named interface {
// Name 用于获取名字。
Name() string
}
type Pet interface {
Animal
Named
}
[Go]接口的运用的更多相关文章
- App开发:模拟服务器数据接口 - MockApi
为了方便app开发过程中,不受服务器接口的限制,便于客户端功能的快速测试,可以在客户端实现一个模拟服务器数据接口的MockApi模块.本篇文章就尝试为使用gradle的android项目设计实现Moc ...
- 干货来袭-整套完整安全的API接口解决方案
在各种手机APP泛滥的现在,背后都有同样泛滥的API接口在支撑,其中鱼龙混杂,直接裸奔的WEB API大量存在,安全性令人堪优 在以前WEB API概念没有很普及的时候,都采用自已定义的接口和结构,对 ...
- 12306官方火车票Api接口
2017,现在已进入春运期间,真的是一票难求,深有体会.各种购票抢票软件应运而生,也有购买加速包提高抢票几率,可以理解为变相的黄牛.对于技术人员,虽然写一个抢票软件还是比较难的,但是还是简单看看123 ...
- Java基础Map接口+Collections工具类
1.Map中我们主要讲两个接口 HashMap 与 LinkedHashMap (1)其中LinkedHashMap是有序的 怎么存怎么取出来 我们讲一下Map的增删改查功能: /* * Ma ...
- Java基础Map接口+Collections
1.Map中我们主要讲两个接口 HashMap 与 LinkedHashMap (1)其中LinkedHashMap是有序的 怎么存怎么取出来 我们讲一下Map的增删改查功能: /* * Ma ...
- java基础_集合List与Set接口
List接口继承了Collection的方法 当然也有自己特有的方法向指定位置添加元素 add(索引,添加的元素); 移除指定索引的元素 remove(索引) 修改指定索引的元素 set ...
- 【WCF】自定义错误处理(IErrorHandler接口的用法)
当被调用的服务操作发生异常时,可以直接把异常的原始内容传回给客户端.在WCF中,服务器传回客户端的异常,通常会使用 FaultException,该异常由这么几个东东组成: 1.Action:在服务调 ...
- PHP以接口方式实现多重继承(完全模拟)--学习笔记
1.UML类图: 2.PHP代码: <?php /** * Created by PhpStorm. * User: andy * Date: 16-11-23 * Time: 下午7:57 ...
- 【微框架】Maven +SpringBoot 集成 阿里大鱼 短信接口详解与Demo
Maven+springboot+阿里大于短信验证服务 纠结点:Maven库没有sdk,需要解决 Maven打包找不到相关类,需要解决 ps:最近好久没有写点东西了,项目太紧,今天来一篇 一.本文简介 ...
- 【接口开发】浅谈 SOAP Webserver 与 Restful Webserver 区别
接口,强大,简单,交互,跨越平台 下面简单阐述这两大接口思想 一 REST: REST是一种架构风格,其核心是面向资源,REST专门针对网络应用设计和开发方式,以降低开发的复杂性,提高系统的可伸缩性. ...
随机推荐
- pscp多线程传输文件
前面说过pscp不支持多线程,所以在此特地实现了一个 程序分三个部分: 1.初始化各种参数,涉及getopt函数的使用 2.重新定义scp,实现传递IP然后远程拷贝 3.启动多线程调用scp,涉及多线 ...
- IIS6配置FastCGI遇到ERROR5的解决方法
FastCGI Error The FastCGI Handler was unable to process the request. ------------------------------- ...
- LN : leetcode 416 Partition Equal Subset Sum
lc 416 Partition Equal Subset Sum 416 Partition Equal Subset Sum Given a non-empty array containing ...
- 【学习笔记】深入理解js原型和闭包(14)——从【自由变量】到【作用域链】
先解释一下什么是“自由变量”. 在A作用域中使用的变量x,却没有在A作用域中声明(即在其他作用域中声明的),对于A作用域来说,x就是一个自由变量.如下图 如上程序中,在调用fn()函数时,函数体中第6 ...
- Summary of 2016 International Trusted Computing and Cloud Security Summit
1) Welcome Remarks 2) The advancement of Cloud Computing and Tursted Computing national st ...
- python+selenium(python基础)
1.编辑器的选择 好刀不误砍柴工,那么我们写代码也需要一个利器,虽然python自带有python shell ,但我们在执行代码的时候,需要开很多窗口,最重要的一点是,代码文件的管理很不方便,笔者推 ...
- MongoDB最简单的入门教程之一 环境搭建
MongoDB是近年来非常流行的一个介于关系数据库和非关系数据库之间的解决方案,特别广泛地应用于国内很多互联网公司,是非关系数据库当中功能最丰富,最像关系数据库的. MongoDB支持的数据结构非常松 ...
- SOE 第五章
SEO第五章 本次课目标: 1. 掌握代码优化 2. 掌握内链优化 一.代码优化 1)<h>标签 代表网页的标题,总共6个级别(h1-h6) 外观上显示字体的大小的修改,其中<h ...
- arx 地址
2014(32位和64位版本) ObjectARX 2014 SDKObjectARX 2014 帮助文档2013(32位和64位版本) ObjectARX 2013 SDKObjectARX 201 ...
- Eclipse Code Recommenders 自动补全(联想)神器
Eclipse Code Recommenders 可以在eclipse市场中下载.自动补全.模糊匹配.非常有用!