接口
Go 语言中的接口是隐式实现的,也就是说,如果一个类型实现了一个接口定义的所有方法,那么它就自动地实现了该接口。因此,我们可以通过将接口作为参数来实现对不同类型的调用,从而实现多态。
package main
import "fmt"
// 1.定义一个接口
type usber interface {
start()
stop()
}
// 2.实现接口中的所有方法
type Computer struct {
name string
model string
}
func (cm Computer) start() {
fmt.Println("启动电脑")
}
func (cm Computer) stop() {
fmt.Println("关闭电脑")
}
type Phone struct {
name string
model string
}
func (p Phone) start() {
fmt.Println("启动手机")
}
func (p Phone) stop() {
fmt.Println("关闭手机")
}
// 3.使用接口定义的方法
func working(u usber) {
u.start()
u.stop()
}
func main() {
cm := Computer{"戴尔", "F1234"}
working(cm) // 启动电脑 关闭电脑
p := Phone{"华为", "M10"}
working(p) // 启动手机 关闭手机
}
注意点: 1、接口中只能有方法的声明不能有方法的实现
2、接口中只能有方法不能有字段
3、只有实现了接口中所有的方法, 才算实现了接口, 才能用该接口类型接收
4、和结构体一样,接口中也可以嵌入接口
5、和结构体一样,接口中嵌入接口时不能嵌入自己
6、接口中嵌入接口时不能出现相同的方法名称
7、空接口类型可以接收任意类型数据
8、使用接口类型和类型转换
- 利用 ok-idiom 模式将接口类型还原为原始类型,s.(Person)这种格式我们称之为: 类型断言。
- 通过 type switch 将接口类型还原为原始类型,注意: type switch 不支持 fallthrought。
package main
import "fmt"
type studier interface {
read()
}
type Person struct {
name string
age int
}
func (p Person) read() {
fmt.Println(p.name, "正在学习")
}
func main() {
var s studier
s = Person{"lnj", 33}
// s.name = "zs" // 报错, 由于s是接口类型, 所以不能访问属性
// 2.定义一个结构体类型变量
//var p Person
// 不能用强制类型转换方式将接口类型转换为原始类型
//p = Person(s) // 报错
// 2.利用ok-idiom模式将接口类型还原为原始类型
// s.(Person)这种格式我们称之为: 类型断言
if p, ok := s.(Person); ok {
p.name = "zs"
fmt.Println(p)
}
// 2.通过 type switch将接口类型还原为原始类型
// 注意: type switch不支持fallthrought
switch p := s.(type) {
case Person:
p.name = "zs3"
fmt.Println(p) // {zs 33}
default:
fmt.Println("不是Person类型")
}
}
对接口的相关补充: 在 Go 语言中,使用接口不一定要定义结构体,我们可以定义任意类型的变量实现相应的接口方法,只要该变量实现了接口中定义的所有方法即可。
而泛型则是一种通用的编程思想,它可以让我们编写一个可以适用于多种不同类型的代码。在 Go 语言中,虽然没有官方支持的泛型实现,但是我们可以使用 interface{}
类型实现类似泛型的功能。因为 interface{}
类型可以表示任意类型的变量,所以我们可以将不同类型的值传入同一个函数或方法中,并在运行时使用类型断言来判断其类型并进行相应的操作。这样可以达到类似泛型的效果,但是需要更多的类型判断和类型转换操作。
package main
import "fmt"
func add(a, b interface{}) (interface{}, interface{}, interface{}) {
//在golang中不支持运算符重载,因此需要判断类型
switch a.(type) {
case int:
return a.(int), b.(int), a.(int) + b.(int)
case float64:
return a.(float64), b.(float64), a.(float64) + b.(float64)
default:
return nil, nil, a.(string) + " " + b.(string)
}
}
func main() {
a := 1
b := 2
c := 2.5
d := 3.7
x, y, z := add(a, b)
fmt.Printf("%v + %v = %v\n", x, y, z)
x, y, z = add(c, d)
fmt.Printf("%v + %v = %v\n", x, y, z)
_, _, z = add("hello", "world")
fmt.Printf("Invalid operation: %v + + %v = %v\n", "hello", "world", z)
}
// 1 + 2 = 3
// 2.5 + 3.7 = 6.2
// Invalid operation: hello + + world = hello world
package main
import "fmt"
type Adder interface {
Add(x, y interface{}) (interface{}, interface{}, interface{})
}
type IntAdder struct {
}
func (i IntAdder) Add(x, y interface{}) (interface{}, interface{}, interface{}) {
return x.(int), y.(int), x.(int) + y.(int)
}
type FloatAdder struct{}
func (f FloatAdder) Add(x, y interface{}) (interface{}, interface{}, interface{}) {
return x.(float64), y.(float64), x.(float64) + y.(float64)
}
func main() {
var a Adder
a = IntAdder{}
x, y, z := a.Add(1, 2)
fmt.Printf("%v + %v = %v\n", x, y, z)
a = FloatAdder{}
x, y, z = a.Add(2.5, 3.7)
fmt.Printf("%v + %v = %v\n", x, y, z)
}
package main
import "fmt"
type Animal interface {
Speak() string
}
type Cat struct{}
func (c Cat) Speak() string {
return "Meow!"
}
type Dog struct{}
func (d Dog) Speak() string {
return "Woof!"
}
func main() {
cat := Cat{}
dog := Dog{}
animals := []Animal{cat, dog}
for _, animal := range animals {
fmt.Println(animal.Speak())
}
}
Meow!
Woof!