GO:interface
一、感受接口
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(参数列表) 返回值列表
...
}
三、注意事项和细节
- 接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的实例;
- 接口中所有的方法都没有方法体,即只定义方法,没有实现该方法;
- 一个自定义类型只有实现了某个接口,才能将该自定义类型的实例赋给该接口类型;
- 只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型;
- 一个自定义类型可以实现多个接口;
- golang的接口不能有任何变量;
- 一个接口(比如 C 接口)可以继承多个别的接口(比如 A、B 接口),这时如果要实现 C 接口,也必须将 A、B 接口中的方法也实现;注意,A、B接口中不能有相同的方法,相当于 C 接口有两个相同的方法,这是不允许的;
- interface 类型默认是一个指针(引用类型),如果没有对 interface 初始化就使用,那么会输出 nil ;
- 空接口 interface{} 没有任何方法,因此所有类型都实现了空接口,即可以把任何一个变量赋给空接口;
- 如果一个自定义类型是使用指针方式实现一个接口的,那么需要将该自定义类型的地址赋给该接口,不然会报错。
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()
}

代码小结:
- 当 B 结构体继承了 A 结构体,那么 B 结构体就"拥有"了 A 结构体的字段和方法,并且可以直接使用;
- 当 B 结构体需要扩展功能,同时不希望去破坏继承关系,则实现某个接口即可。因此可以认为:实现接口可以看做是对继承的一种补充。
接口与继承总结:
①接口与继承解决的问题不同
- 继承的价值主要在于:解决代码的复用性和可维护性。
- 接口的价值主要在于:设计,设计好各种规范(方法),让其它自定义类型去实现这些方法。
②接口比继承更加灵活
- 继承是 is - xx 的关系,而接口是 like - xx 的关系。为什么这样说? --> 我们不能说猴子是一条鱼,但可以说:猴子可以像鱼儿一样游泳。
③接口在一定程度上实现代码解耦
GO:interface的更多相关文章
- iOS开发工具Xcode:Interface Builder
简介: Interface Builder(IB)是Mac OS X平台下用于设计和测试用户界面(GUI)的应用程序(非开源).为了生成GUI,IB并不是必需的,实际上Mac OS X下所有的用户界面 ...
- 面向对象_06【抽象类:abstract、接口:interface、实现:implements】
抽象类:abstract抽象:没有足够的描述功能,事物不具体的描述,却又有共性. 特点: 1,方法只有声明没有实现时,该方法就是抽象方法,需要被abstract修饰,抽象方法必须定义在抽象类中,该类也 ...
- 静态,关键字:static 接口,IUSB , API 接口关键字:interface
//静态 //普通成员 //普通成员是属于对象的 //静态成员 //静态成员属于类的 //关键字:static //self关键字:在类里面代表该类 //在静态方法里面不能调用普通成员 //在普通方法 ...
- [你必须知道的.NET]第二十七回:interface到底继承于object吗?
发布日期:2009.03.05 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 在.NET世界里,我们常常听到的一句话莫过于“S ...
- go:interface{}、断言与类型转换
interface{}可用于向函数传递任意类型的变量,但对于函数内部,该变量仍然为interface{}类型(空接口类型), 不清楚这点将可能导致错误.如以下代码: package main impo ...
- java8新特性:interface中的static方法和default方法
java8中接口有两个新特性,一个是静态方法,一个是默认方法. static方法 java8中为接口新增了一项功能:定义一个或者多个静态方法. 定义用法和普通的static方法一样: public i ...
- Go语言第一深坑:interface 与 nil 的比较
interface简介 Go 语言以简单易上手而著称,它的语法非常简单,熟悉 C++,Java 的开发者只需要很短的时间就可以掌握 Go 语言的基本用法. interface 是 Go 语言里所提供的 ...
- java基础13 接口(及关键字:interface、implements)
接口 1.接口的定义格式 interface 接口名{ } interface :接口的关键字 implements:实现接口的关键字 2.接口的作用 1.程序的解耦.(低耦合) 2.定 ...
- 面试题思考:interface和abstract的区别
抽象类(abstract) 含有abstract修饰符的class即为抽象类,abstract 类不能创建的实例对象. 含有abstract方法的类必须定义为abstract class,abstra ...
- 注解:@interface 自定义注解的语法
自定义注解: 使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节.在定义注解时,不能继承其他的注解或接口 ...
随机推荐
- P4692 [Ynoi2016]谁的梦
传送门 分别考虑每一种颜色对答案的贡献.每种颜色的贡献就是他出现的区间个数,那么可以用总区间减去不包含它的区间个数,把每一个序列里不包含它的区间个数加起来,然后不同序列用乘法原理计算即可 于是我辛辛苦 ...
- python 之 random 模块、 shutil 模块、shelve模块、 xml模块
6.12 random 模块 print(random.random()) (0,1)----float 大于0且小于1之间的小数 print(random.randint(1,3)) [1,3] 大 ...
- ExtWebComponents
我们很高兴地宣布Sencha ExtWebComponents的早期版本现已推出.ExtWebComponents提供了数百个预构建的UI组件,您可以轻松地将它们集成到使用任何框架构建的Web应用程序 ...
- ngxin做http强制跳转https,接口的POST请求变成GET
http强制跳转https出现了问题.修改nginx配置如下即可解决: server { listen 80; server_name *.snsprj.cn; return 307 https:// ...
- c++模板专门化
#include <iostream> #include<cstring> using namespace std; template <typename T> T ...
- codeforces 149D Coloring Brackets (区间DP + dfs)
题目链接: codeforces 149D Coloring Brackets 题目描述: 给一个合法的括号串,然后问这串括号有多少种涂色方案,当然啦!涂色是有限制的. 1,每个括号只有三种选择:涂红 ...
- linux查找命令(find)
linux查找命令(find) 命令格式: find [目录] [选项] [选项的条件] 选项: -name:文件名称查找 -size:文件的大小来查找 -perm:文件的权限来查找 ①根据文件的名称 ...
- 18.3.2从Class上获取信息(构造器)
获取构造器信息 package d18_3_1; import java.lang.reflect.Constructor; import java.util.Arrays; /** * 获取构造器的 ...
- apache mod_alias模块功能介绍
我觉得mod_alias根mod_rewrite挺像的,都可以实现url的重写,而mod_alias可以实现简单的url重写的功能 ,而mod_rewrite可以实现比较复杂的重写.mod_alias ...
- memcache的分布式配置
public static class MemcacheHelper { private static MemcachedClient mc; static MemcacheHelper() { St ...