一、继承
在 Go 中,并没有传统意义上的继承机制,但是可以通过嵌入结构体来实现类似继承的效果。具体来说,
可以通过在一个结构体中嵌入另一个结构体的方式,
让前者继承后者的属性和方法。
假设我们有一个名为 Animal 的结构体:
type Animal struct {
name string
}
func (a *Animal) Move() {
fmt.Printf("%s is moving\n", a.name)
}
然后我们可以通过嵌入 Animal 结构体来定义一个新的结构体 Dog:
type Dog struct {
*Animal // 嵌入 Animal 结构体
}
func main() {
dog := &Dog{&Animal{"doggy"}}
dog.Move() // 调用 Animal 结构体中的 Move 方法
}
这里的 *Animal
表示嵌入了 Animal 结构体,这样 Dog 结构体就继承了 Animal 结构体中的属性和方法。在这个例子中,我们调用了 Dog 结构体中没有定义的 Move 方法,实际上是调用了 Animal 结构体中的 Move 方法。
需要注意的是,Go 中的嵌入结构体只是一种语法糖,实际上是在编译时将嵌入的结构体中的字段和方法复制到了当前结构体中。因此,如果一个结构体嵌入了多个结构体,而这些结构体中存在同名的字段或方法,那么在使用时就需要使用全限定名
来调用,以避免歧义。
二、接口
2.1 接口定义
接口(interface)
是一种合约类型(contract type)
,定义了一组方法,一个类型只要实现了这些方法,就可以被认为是实现了这个接口。
2.2 接口实现
一个类型如果拥有一个接口需要的所有方法,那么这个类型就实现了这个接口
假设我们定义一个Usb的接口,手机和电脑都可以插入,并提供了一个Start方法
type Usb interface {
Start()
}
现在我们提供了小米和苹果手机去插入
type Phone struct {
}
type Xiaomi struct {
}
//phone结构体实现Usb的方法
func (p Phone)Start(){
fmt.Println("我的苹果手机插入了!!!")
}
func (p Phone)Stop(){
fmt.Println("我的苹果手机拔出了!!!")
}
// xiaomi结构体实现Usb的方法
func (x Xiaomi)Start(){
fmt.Println("我的小米手机插入了!!!")
}
func (x Xiaomi)Start(){
fmt.Println("我的小米手机插入了!!!")
}
上述两个结构体实现了Usb的所有方法,那么我们就可以说该结构体已经实现了Usb接口,现在我们进行调用。
func (c Computer) Working(usb ...Usb) {
for _, u := range usb {
u.Start()
u.Stop()
}
}
我们这块使用了多态的思想(一个方法在不同的类型中具有不同的行为),定义一个方法Working去处理
c := Computer{}
p := Phone{}
x := Xiaomi{}
//多态的体现
c.Working(p,x)
2.3 接口注意事项
1、接口是一种引用类型,不能直接实例化
2、接口可以作为函数的参数和返回值类型。
3、实现接口的类型必须实现接口中定义的所有方法。
4、如果一个接口类型的值存储了实现该接口的类型的值,那么可以通过类型断言将接口类型的值转换为实现该接口的类型的值。
5、接口的零值为 nil,如果一个接口变量存储了 nil 值,则它不包含任何值,调用它的方法会导致运行时错误。
三、类型断言
3.1 定义
在Go语言中,类型断言(Type Assertion)是一种
将接口类型的值转换为其它类型的方法
,通过它可以判断一个接口类型的变量是否实现了某个具体的接口或者是一个具体的类型。
3.2 类型断言的方式
- 基于接口的类型断言
基于接口值的类型断言使用语法 x.(T)
,其中 x 是接口类型的值,T 是目标类型。如果 x 的底层类型是 T,则类型断言将返回一个 T 类型的值;否则,它将引发一个运行时错误。例如:
var i interface{} = "hello"
s := i.(string) // 正确,s 的值为 "hello"
n := i.(int) // 错误,将导致运行时错误
需要注意的是,在使用基于接口值的类型断言时,需要确保接口值不为 nil,否则将引发运行时错误。因此,可以使用 if 语句结合类型断言来检查接口值的类型,例如:
var i interface{} = "hello"
if s, ok := i.(string); ok {
fmt.Println("i is a string:", s)
} else {
fmt.Println("i is not a string")
}