1. Go语言的多态性
多态是面向对象语言中的一个重要特性,能够提高代码的可扩展性和重用性。在Go语言中,多态可以通过接口实现。接口是一种抽象类型,定义了一组方法,实现了这些方法的类型就可以称为该接口的实现类型。因此,同一个接口可以被不同的类型实现,从而实现多态性。
Go语言的接口与其他语言中的接口有所不同,它并不需要显式地声明实现了哪个接口,只要实现了接口中定义的方法,该类型就认为实现了这个接口。
1.1 接口的定义
在Go语言中,使用type
关键字和interface
关键字来定义一个接口,语法如下:
type 接口名 interface {
方法1()
方法2()
...
}
其中,接口名
是用户定义的标识符,用来表示该接口的名称;方法1()
、方法2()
等表示接口中的方法。
1.2 接口的实现
在Go语言中,一个类型如果实现了一个接口中定义的所有方法,即称该类型实现了该接口。一个类型可以实现多个接口,也可以实现一个接口的不同版本。
接口的实现是隐式的,即一个类型只需要定义与接口中所有方法同名、同参数、同返回值的方法,就可以认为该类型实现了该接口。
下面是一个实现了Shaper
接口的程序:
type Shaper interface {
Area() float64
}
type Rect struct {
width, height float64
}
func (r Rect) Area() float64 {
return r.width * r.height
}
func main() {
var s Shaper
s = Rect{5.0, 4.0}
fmt.Println("Area of rectangle: ", s.Area())
}
在这个例子中,我们定义了一个Shaper
接口,它只有一个方法Area
,返回一个float64
类型。
然后我们定义了一个Rect
类型,它实现了Shaper
接口中的Area
方法。最后,在main
函数中,我们定义了一个Shaper
类型的变量s
,并将其赋值为一个Rect
类型的值。然后我们调用s.Area()
方法,返回Rect
类型的面积。
2. 接口的多态性
接口的多态性是指,一个接口变量可以存储任何实现了该接口的类型的值。因为不同类型实现了相同的接口,在使用时,我们可以使用相同的方法来调用这些类型的方法。
2.1 空接口
空接口是指没有定义任何方法的接口,也可以理解为没有限制的接口。因为空接口没有任何方法,所以可以用来存储任何值。
下面是一个空接口的例子:
var empty interface{}
empty = 42
fmt.Println(empty)
empty = "hello"
fmt.Println(empty)
在这个例子中,我们定义了一个空接口empty
,并将empty
变量分别赋值为一个整数和一个字符串。由于空接口可以存储任何值,所以输出结果不会出错。
2.2 接口变量的赋值
Go语言中,一个接口类型可以被另一个实现了该接口的类型赋值,这样就可以将一个具体类型的值转换成一个抽象类型的值。
type Shaper interface {
Area() float64
}
type Rect struct {
width, height float64
}
func (r Rect) Area() float64 {
return r.width * r.height
}
func main() {
var s Shaper
r := Rect{5.0, 4.0}
s = r
fmt.Println("Area of rectangle: ", s.Area())
}
在这个例子中,我们定义了一个Rect
类型,并实现了Shaper
接口中的Area
方法。然后,我们将r
变量赋值给一个Shaper
类型的变量s
。最终,我们通过s.Area()
方法来调用Rect
类型的Area()
方法,计算出矩形的面积。
3. 接口类型的判断和转换
由于接口类型可以存储任何值,所以我们需要在使用中判断接口变量存储的是什么类型的值,然后再对该值进行操作。
3.1 接口类型的判断
在Go语言中,可以使用类型断言来判断一个接口变量中存储的是什么类型的值。
类型断言可以分为两种:
类型查询:判断接口变量中存储的是否为某个类型的值,如果是,返回该值和true
;否则返回nil
和false
。
类型转换:将接口变量中存储的值转换成某个类型的值。如果接口变量中存储的值的类型不是目标类型,则转换失败,返回nil
和false
。
下面是一个类型查询的例子:
var i interface{} = "hello"
s, ok := i.(string)
if ok {
fmt.Println(s)
}
在这个例子中,我们定义了一个空接口i
,并将其赋值为一个字符串。然后我们使用i.(string)
语法来判断i
中存储的是否为字符串类型,如果是,就将其转换为字符串并将其赋值给s
变量,同时将ok
变量赋值为true
。最后,我们打印出s
变量的值。
3.2 接口类型的转换
同样地,在Go语言中,可以使用类型断言来将一个接口变量中存储的值转换成某个类型的值。
下面是一个类型转换的例子:
var i interface{} = 42
j, ok := i.(int)
if ok {
fmt.Println(j)
}
在这个例子中,我们定义了一个空接口i
,并将其赋值为一个整数。然后我们使用i.(int)
语法来将i
中存储的值转换为整数类型,并将其赋值给j
变量,同时将ok
变量赋值为true
。最后,我们打印出j
变量的值。
4. 总结
Go语言通过接口实现了多态性的特性,使得代码的可扩展性和重用性更高。接口的实现和转换都是隐式的,只需要实现相同名称、参数和返回值的方法,就可以被认为是实现了该接口。接口变量可以存储任何实现了该接口的类型的值,实现了接口的类型可以被隐式地转换成该接口类型。为了操作接口变量中存储的具体类型的值,可以使用类型断言进行类型查询和类型转换。