一、感受接口

type Usb interface {
Connect()
Disconnect()
}
// 手机
type Phone struct {}
// 相机
type Camera struct {}
// 计算机
type Computer struct {}
// 手机实现接口所有方法
func (p Phone) Connect() {
fmt.Println("手机连接中...")
}
func (p Phone) Disconnect() {
fmt.Println("手机断开连接中...")
}
// 相机实现接口所有方法
func (c Camera) Connect() {
fmt.Println("相机连接中...")
}
func (c Camera) Disconnect() {
fmt.Println("相机断开连接中...")
}
// Working方法,接收一个Usb接口类型变量
func (c Computer) Working(usb Usb) {
// 通过接口变量来调用Connect和Disconnect方法
usb.Connect()
usb.Disconnect()
}
func main() {
// 创建结构体实例
phone := Phone{}
camera := Camera{}
computer := Computer{}
// 关键点
computer.Working(phone)
computer.Working(camera)
}
// 输出如下
// 手机连接中...
// 手机断开连接中...
// 相机连接中...
// 相机断开连接中...

当传入一个phone,usb就能识别是手机,传入camera,usb就能识别是相机,并别分调用其相应的方法。这很明显就是多态呀!!!

func (c Computer) Working(usb Usb) {
usb.Connect()
usb.Disconnect()
}
func main() {
phone := Phone{}
camera := Camera{}
computer := Computer{}
computer.Working(phone)
computer.Working(camera)
}

二、接口介绍

interface 类型可以定义一组方法,但是这些方法不需要实现。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现了这个接口。

语法:

type 接口名 interface {
method1(参数列表) 返回值列表
method2(参数列表) 返回值列表
...
}

三、注意事项和细节

  1. 接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的实例;
  2. 接口中所有的方法都没有方法体,即只定义方法,没有实现该方法;
  3. 一个自定义类型只有实现了某个接口,才能将该自定义类型的实例赋给该接口类型;
  4. 只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型;
  5. 一个自定义类型可以实现多个接口;
  6. golang的接口不能有任何变量;
  7. 一个接口(比如 C 接口)可以继承多个别的接口(比如 A、B 接口),这时如果要实现 C 接口,也必须将 A、B 接口中的方法也实现;注意,A、B接口中不能有相同的方法,相当于 C 接口有两个相同的方法,这是不允许的;
  8. interface 类型默认是一个指针(引用类型),如果没有对 interface 初始化就使用,那么会输出 nil ;
  9. 空接口 interface{} 没有任何方法,因此所有类型都实现了空接口,即可以把任何一个变量赋给空接口;
  10. 如果一个自定义类型是使用指针方式实现一个接口的,那么需要将该自定义类型的地址赋给该接口,不然会报错。
type AInterface interface {
Eat()
} type Person struct {
Name string
} func (p Person) Eat() {
fmt.Printf("%s正在吃饭...\n", p.Name) // 佩奇正在吃饭...
} func main() {
p := Person{"佩奇"}
var a AInterface = p // 接口可以指向一个实现了该接口的自定义类型实例
a.Eat()
}

第1、3点

type AInterface interface {
Eat()
} type BInterface interface {
Sleep()
} type Person struct {
Name string
} func (p Person) Eat() {
fmt.Printf("%s正在吃饭...\n", p.Name) // 佩奇正在吃饭...
} func (p Person) Sleep() {
fmt.Printf("%s正在睡觉...\n", p.Name) // 佩奇正在睡觉...
} func main() {
p := Person{"佩奇"}
var a AInterface = p
var b BInterface = p
a.Eat()
b.Sleep()
}

第5点

type AInterface interface {
Eat()
} type BInterface interface {
Sleep()
} type CInterface interface {
AInterface
BInterface
Study()
} type Person struct {
Name string
} func (p Person) Eat() {
fmt.Printf("%s正在吃饭...\n", p.Name) // 佩奇正在吃饭...
} func (p Person) Sleep() {
fmt.Printf("%s正在睡觉...\n", p.Name) // 佩奇正在吃饭...
} func (p Person) Study() {
fmt.Printf("%s正在学习...\n", p.Name) // 佩奇正在学习...
} func main() {
p := Person{"佩奇"}
var c CInterface = p
c.Eat()
c.Sleep()
c.Study()
}

第7点

type T interface {}

type Integer int

func main() {
var int1 Integer
int2 := Integer(100)
var t T
t = int1
fmt.Println(t) //
t = int2
fmt.Println(t) //
}

第9点

type A interface {
Eat()
} type Person struct {
Name string
} // 使用 Person 指针类型实现一个接口的方法
func (p *Person) Eat() {
fmt.Printf("%s正在吃饭...", p.Name)
} func main() {
p := Person{"佩奇"}
//var a A = p // 错误!!!因为Person类型没有实现A接口,修改如下
var a A = &p
a.Eat()
}

第10点

四、接口最佳实践

实现对 Student 结构体切片的排序:sort.Sort(data Interface)

package main

import (
"fmt"
"math/rand"
"sort"
"time"
) type Student struct {
Name string
Score int
} type StudentSlice []Student func (ss StudentSlice) Len() int {
return len(ss)
}
// Less方法决定使用什么标准进行排序
// 这里按成绩从小到大排序
func (ss StudentSlice) Less(i, j int) bool {
return ss[i].Score < ss[j].Score
}
func (ss StudentSlice) Swap(i, j int) {
ss[i], ss[j] = ss[j], ss[i]
} func main() {
var ss StudentSlice
rand.Seed(time.Now().UnixNano())
for i := 0; i < 10; i++ {
student := Student{
Name: fmt.Sprintf("学生%d号", i),
Score: rand.Intn(100),
}
ss = append(ss, student)
}
// 排序前的顺序
for _, v := range ss {
fmt.Println(v)
}
// 调用sort.Sort方法
sort.Sort(ss)
fmt.Println()
// 排序后的顺序
for _, v := range ss {
fmt.Println(v)
}
}

输出结果:

五、接口与继承的区别

package main

import "fmt"

type Monkey struct {
Name string
} type LittleMonkey struct {
Monkey // 继承
} type BridAble interface {
Flying()
}
type FishAble interface {
Swimming()
} func (m *Monkey) Climbing() {
fmt.Printf("%s天生就会爬树...\n", m.Name)
} func (ls *LittleMonkey) Flying() {
fmt.Printf("%s通过学习,会飞翔...\n", ls.Name)
} func (ls *LittleMonkey) Swimming() {
fmt.Printf("%s通过学习,会游泳...\n", ls.Name)
} func main() {
wk := LittleMonkey{Monkey{"小猴子"}}
wk.Climbing()
wk.Flying()
wk.Swimming()
}

代码小结:

  1. 当 B 结构体继承了 A 结构体,那么 B 结构体就"拥有"了 A 结构体的字段和方法,并且可以直接使用;
  2. 当 B 结构体需要扩展功能,同时不希望去破坏继承关系,则实现某个接口即可。因此可以认为:实现接口可以看做是对继承的一种补充。

接口与继承总结:

①接口与继承解决的问题不同

  • 继承的价值主要在于:解决代码的复用性可维护性
  • 接口的价值主要在于:设计,设计好各种规范(方法),让其它自定义类型去实现这些方法。

②接口比继承更加灵活

  • 继承是 is - xx 的关系,而接口是 like - xx 的关系。为什么这样说? --> 我们不能说猴子是一条鱼,但可以说:猴子可以像鱼儿一样游泳。

③接口在一定程度上实现代码解耦

GO:interface的更多相关文章

  1. iOS开发工具Xcode:Interface Builder

    简介: Interface Builder(IB)是Mac OS X平台下用于设计和测试用户界面(GUI)的应用程序(非开源).为了生成GUI,IB并不是必需的,实际上Mac OS X下所有的用户界面 ...

  2. 面向对象_06【抽象类:abstract、接口:interface、实现:implements】

    抽象类:abstract抽象:没有足够的描述功能,事物不具体的描述,却又有共性. 特点: 1,方法只有声明没有实现时,该方法就是抽象方法,需要被abstract修饰,抽象方法必须定义在抽象类中,该类也 ...

  3. 静态,关键字:static 接口,IUSB , API 接口关键字:interface

    //静态 //普通成员 //普通成员是属于对象的 //静态成员 //静态成员属于类的 //关键字:static //self关键字:在类里面代表该类 //在静态方法里面不能调用普通成员 //在普通方法 ...

  4. [你必须知道的.NET]第二十七回:interface到底继承于object吗?

    发布日期:2009.03.05 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 在.NET世界里,我们常常听到的一句话莫过于“S ...

  5. go:interface{}、断言与类型转换

    interface{}可用于向函数传递任意类型的变量,但对于函数内部,该变量仍然为interface{}类型(空接口类型), 不清楚这点将可能导致错误.如以下代码: package main impo ...

  6. java8新特性:interface中的static方法和default方法

    java8中接口有两个新特性,一个是静态方法,一个是默认方法. static方法 java8中为接口新增了一项功能:定义一个或者多个静态方法. 定义用法和普通的static方法一样: public i ...

  7. Go语言第一深坑:interface 与 nil 的比较

    interface简介 Go 语言以简单易上手而著称,它的语法非常简单,熟悉 C++,Java 的开发者只需要很短的时间就可以掌握 Go 语言的基本用法. interface 是 Go 语言里所提供的 ...

  8. java基础13 接口(及关键字:interface、implements)

    接口 1.接口的定义格式 interface 接口名{ } interface :接口的关键字 implements:实现接口的关键字 2.接口的作用 1.程序的解耦.(低耦合)        2.定 ...

  9. 面试题思考:interface和abstract的区别

    抽象类(abstract) 含有abstract修饰符的class即为抽象类,abstract 类不能创建的实例对象. 含有abstract方法的类必须定义为abstract class,abstra ...

  10. 注解:@interface 自定义注解的语法

      自定义注解: 使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节.在定义注解时,不能继承其他的注解或接口 ...

随机推荐

  1. P4692 [Ynoi2016]谁的梦

    传送门 分别考虑每一种颜色对答案的贡献.每种颜色的贡献就是他出现的区间个数,那么可以用总区间减去不包含它的区间个数,把每一个序列里不包含它的区间个数加起来,然后不同序列用乘法原理计算即可 于是我辛辛苦 ...

  2. python 之 random 模块、 shutil 模块、shelve模块、 xml模块

    6.12 random 模块 print(random.random()) (0,1)----float 大于0且小于1之间的小数 print(random.randint(1,3)) [1,3] 大 ...

  3. ExtWebComponents

    我们很高兴地宣布Sencha ExtWebComponents的早期版本现已推出.ExtWebComponents提供了数百个预构建的UI组件,您可以轻松地将它们集成到使用任何框架构建的Web应用程序 ...

  4. ngxin做http强制跳转https,接口的POST请求变成GET

    http强制跳转https出现了问题.修改nginx配置如下即可解决: server { listen 80; server_name *.snsprj.cn; return 307 https:// ...

  5. c++模板专门化

    #include <iostream> #include<cstring> using namespace std; template <typename T> T ...

  6. codeforces 149D Coloring Brackets (区间DP + dfs)

    题目链接: codeforces 149D Coloring Brackets 题目描述: 给一个合法的括号串,然后问这串括号有多少种涂色方案,当然啦!涂色是有限制的. 1,每个括号只有三种选择:涂红 ...

  7. linux查找命令(find)

    linux查找命令(find) 命令格式: find [目录] [选项] [选项的条件] 选项: -name:文件名称查找 -size:文件的大小来查找 -perm:文件的权限来查找 ①根据文件的名称 ...

  8. 18.3.2从Class上获取信息(构造器)

    获取构造器信息 package d18_3_1; import java.lang.reflect.Constructor; import java.util.Arrays; /** * 获取构造器的 ...

  9. apache mod_alias模块功能介绍

    我觉得mod_alias根mod_rewrite挺像的,都可以实现url的重写,而mod_alias可以实现简单的url重写的功能 ,而mod_rewrite可以实现比较复杂的重写.mod_alias ...

  10. memcache的分布式配置

    public static class MemcacheHelper { private static MemcachedClient mc; static MemcacheHelper() { St ...