在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]接口的运用的更多相关文章

  1. App开发:模拟服务器数据接口 - MockApi

    为了方便app开发过程中,不受服务器接口的限制,便于客户端功能的快速测试,可以在客户端实现一个模拟服务器数据接口的MockApi模块.本篇文章就尝试为使用gradle的android项目设计实现Moc ...

  2. 干货来袭-整套完整安全的API接口解决方案

    在各种手机APP泛滥的现在,背后都有同样泛滥的API接口在支撑,其中鱼龙混杂,直接裸奔的WEB API大量存在,安全性令人堪优 在以前WEB API概念没有很普及的时候,都采用自已定义的接口和结构,对 ...

  3. 12306官方火车票Api接口

    2017,现在已进入春运期间,真的是一票难求,深有体会.各种购票抢票软件应运而生,也有购买加速包提高抢票几率,可以理解为变相的黄牛.对于技术人员,虽然写一个抢票软件还是比较难的,但是还是简单看看123 ...

  4. Java基础Map接口+Collections工具类

    1.Map中我们主要讲两个接口 HashMap  与   LinkedHashMap (1)其中LinkedHashMap是有序的  怎么存怎么取出来 我们讲一下Map的增删改查功能: /* * Ma ...

  5. Java基础Map接口+Collections

    1.Map中我们主要讲两个接口 HashMap  与   LinkedHashMap (1)其中LinkedHashMap是有序的  怎么存怎么取出来 我们讲一下Map的增删改查功能: /* * Ma ...

  6. java基础_集合List与Set接口

    List接口继承了Collection的方法  当然也有自己特有的方法向指定位置添加元素   add(索引,添加的元素); 移除指定索引的元素   remove(索引) 修改指定索引的元素   set ...

  7. 【WCF】自定义错误处理(IErrorHandler接口的用法)

    当被调用的服务操作发生异常时,可以直接把异常的原始内容传回给客户端.在WCF中,服务器传回客户端的异常,通常会使用 FaultException,该异常由这么几个东东组成: 1.Action:在服务调 ...

  8. PHP以接口方式实现多重继承(完全模拟)--学习笔记

     1.UML类图: 2.PHP代码: <?php /** * Created by PhpStorm. * User: andy * Date: 16-11-23 * Time: 下午7:57 ...

  9. 【微框架】Maven +SpringBoot 集成 阿里大鱼 短信接口详解与Demo

    Maven+springboot+阿里大于短信验证服务 纠结点:Maven库没有sdk,需要解决 Maven打包找不到相关类,需要解决 ps:最近好久没有写点东西了,项目太紧,今天来一篇 一.本文简介 ...

  10. 【接口开发】浅谈 SOAP Webserver 与 Restful Webserver 区别

    接口,强大,简单,交互,跨越平台 下面简单阐述这两大接口思想 一 REST: REST是一种架构风格,其核心是面向资源,REST专门针对网络应用设计和开发方式,以降低开发的复杂性,提高系统的可伸缩性. ...

随机推荐

  1. webkit滤镜

    -webkit-filter: grayscale(1);/*灰度*/ -webkit-filter: sepia(1);/*褐色*/ -webkit-filter: saturate(1);/*饱和 ...

  2. PDO相关函数

    (PHP 5 >= 5.1.0, PHP 7, PECL pdo >= 0.1.0) PDO::__construct — 创建一个表示数据库连接的 PDO 实例 说明 PDO::__co ...

  3. AJPFX浅谈Java 性能优化之垃圾回收(GC)

    ★JVM 的内存空间 在 Java 虚拟机规范中,提及了如下几种类型的内存空间: ◇栈内存(Stack):每个线程私有的.◇堆内存(Heap):所有线程公用的.◇方法区(Method Area):有点 ...

  4. dubbo系列--重要概念介绍

    dubbo架构图 节点角色说明 整体设计 proxyFactory:就是为了获取一个接口的代理类,例如获取一个远程接口的代理.它有2个方法,代表2个作用 getInvoker:针对server端,将服 ...

  5. 【学习笔记】OSG中相机参数的更改

    #pragma comment(lib, "osg.lib") #pragma comment(lib, "osgDB.lib") #pragma commen ...

  6. viewport实现html页面动态缩放/meta viewport/viewport

    页面默认缩放比例为1,最小宽度为375px,在小于375px出现水平滚动条的时候重新计算显示比例缩小界面, <!DOCTYPE html> <html lang="en&q ...

  7. TigerGraph REST++API

    简介 - 什么是REST ++? TigerGraph TM 系统使用着名的REpresentational State Transfer(REST)架构来管理与TigerGraph核心组件,图形处理 ...

  8. varchar2(100 char)是什么意思

    最佳答案   varchar2(100 char)最长可以插入100个任意字符而varchar2(100)最长可以插入100个英文字符

  9. 用python+pygame写贪吃蛇小游戏

    因为python语法简单好上手,前两天在想能不能用python写个小游戏出来,就上网搜了一下发现了pygame这个写2D游戏的库.了解了两天再参考了一些资料就开始写贪吃蛇这个小游戏. 毕竟最开始的练手 ...

  10. MPP(大规模并行处理)简介

    1. 什么是MPP? MPP (Massively Parallel Processing),即大规模并行处理,在数据库非共享集群中,每个节点都有独立的磁盘存储系统和内存系统,业务数据根据数据库模型和 ...