接口(interface)
接口可以定义一组方法但不需要实现,并且接口不能包含任何变量,到某个自定义类型(如结构体)要使用的时候,在根据具体情况把这些方法写出来。
基本语法
type 接口名 interface{
method1(参数列表) 返回值列表
method2(参数列表) 返回值列表
}
实现接口所有方法
func (t 自定义类型) method1(参数列表) 返回值列表 {
// 方法实现
}
func (t 自定义类型) method12参数列表) 返回值列表 {
// 方法实现
}
说明
- 接口里的所有方法都没有方法体,即接口的方法都是没有实现的方法,接口体现了程序设计的多态和高内聚低耦合的思想
- Golang中的接口,不需要显示的实现,只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此,golang中没有implement这样的关键字。
代码示例
package main
import "fmt"
// 定义一个USB接口
type Usb interface {
Start()
Stop()
}
// phone结构体
type Phone struct {
}
// Phone 实现接口所有方法
func (p Phone) Start() {
fmt.Println("手机开始工作。。。")
}
func (p Phone) Stop() {
fmt.Println("手机停止工作。。。")
}
// 相机结构体
type Camera struct {
}
// Camera 实现接口所有方法
func (c Camera) Start() {
fmt.Println("相机开始工作.....")
}
func (c Camera) Stop() {
fmt.Println("相机停止工作...")
}
type Computer struct {
}
// 方法Working 接收一个USB接口类型变量
// 只要实现了 Usb接口
func (c Computer) Working(usb Usb) {
usb.Start()
usb.Stop()
}
func main() {
computer:= Computer{}
phone := Phone{}
camera := Camera{}
computer.Working(phone)
computer.Working(camera)
}
输出结果:
手机开始工作。。。
手机停止工作。。。
相机开始工作.....
相机停止工作...
注意事项
- 接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量(实例) 代码示例:
package main
import "fmt"
type AInterface interface {
Say()
}
type Stu struct {
Name string
}
func (s Stu) Say() {
fmt.Println("stu Say()")
}
func main() {
var s Stu
var a AInterface = s
a.Say()
}
// 输出: stu Say()
- 接口中所有的方法都没有方法体即都是没有实现的方法
- 在Golang中,一个自定义类型需要将某个接口的所有方法都实现,我们说这个自定义类实现了该接口
- 一个自定义接口实现了某个接口才能将该自定义的实例(变量)赋给接口类型
- 只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型
type AInterface interface {
Say()
}
// 自定义类型
type integer int
func (i integer) Say() {
fmt.Println("integer Say i= ", i)
}
func main() {
var i integer = 10
var b AInterface = i
b.Say()
}
- 一个自定义类型可以实现多个接口
type AInterface interface {
Say()
}
type BInterface interface {
Hello()
}
type Monster struct {
}
func (m Monster) Hello() {
fmt.Println("Monster Hello ")
}
func (m Monster) Say() {
fmt.Println("Monster Say ")
}
func main() {
// Monster 实现了 AInterface 和 BInterface
var m Monster
var a2 AInterface = m
var b2 BInterface = m
a2.Say()
b2.Hello()
}
- interface类型默认是一个指针(引用类型),如果没有对interface初始化就使用那么会输出nil
- 空接口interface{}没有任何方法,所以所有类型都实现了空接口
// 空接口
type T interface {
}
func main() {
var s Stu
var a AInterface = s
a.Say()
// 可以给空接口赋值
var t = s
fmt.Println(t)
var t2 interface{} = s
var num1 float64 = 90.0
t2 = num1
fmt.Println(t2, t)
}
接口经典应用实例
对一个自定义的结构体 学生按照成绩降序输出学生切片
// 学生结构体
type Stu struct {
Name string
Age int
Score float64
}
// 学生切片
type stuSlice []Stu
// 实现排序接口
func (ss stuSlice) Len() int {
return len(ss)
}
func (ss stuSlice) Less(i, j int) bool {
return ss[i].Score > ss[j].Score
}
func (ss stuSlice) Swap(i, j int) {
ss[i], ss[j] = ss[j], ss[i]
}
func main() {
// 测试
var students stuSlice
for i := 0; i < 10; i++ {
f, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", rand.Float64()*40+60), 64)
stu := Stu{
Name: fmt.Sprintf("学生%d", rand.Intn(100)),
Age: rand.Intn(100),
Score: f,
}
students = append(students, stu)
}
// 排序前
fmt.Println("排序前-----------")
fmt.Println(students)
sort.Sort(students)
fmt.Println("排序后-----------")
fmt.Println(students)
}
// 结果实例:
排序前-----------
[{学生87 47 84.19} {学生81 18 77.51} {学生40 56 62.63} {学生94 11 72.04} {学生89 28 68.57} {学生11 45 78.76} {学生6 95 87.16} {学生28 58 74.43} {学生47 87 71.72}{学生90 15 68.26}]
排序后-----------
[{学生6 95 87.16} {学生87 47 84.19} {学生11 45 78.76} {学生81 18 77.51} {学生28 58 74.43} {学生94 11 72.04} {学生47 87 71.72} {学生89 28 68.57} {学生90 15 68.26} {学生40 56 62.63}]