1 接口类型介绍
接口是一种抽象的类型,它不会暴露出它所代表的对象的内布值的结构和这个对象所支持的基础操作的几乎,它只会展示出它们自己的方法,因为接口类型不能将其实例化。
2 接口的定义和实现
- 1)接口名字一般以er结尾命名,例如Windowser。
- 2)接口只有方法的声明,没有实现,没有数据字段。
- 3)接口可以匿名嵌入其它接口,或嵌入到结构中。
package main
import "fmt"
// 接口的定义
type Humaner interface {
// 方法,只有声明,没有实现,由别的类型去实现
sayhi()
}
type Student struct {
name string
id int
}
func (t *Student) sayhi(){
fmt.Printf("Student[%s, %d], sayhi\n", t.name, t.id)
}
type Teacher struct {
addr string
group string
}
func (t *Teacher) sayhi(){
fmt.Printf("Teacher[%s, %s], sayhi\n", t.addr, t.group)
}
type MyStr string
func (t *MyStr) sayhi(){
fmt.Printf("MyStr[%s], sayhi\n", *t)
}
func main(){
// 1. 定义该接口变量,值由实现了 该接口中的方法 的类型赋值
var i Humaner
s := &Student{"hc", 1} // 为指针是因为接口实现的方法的接收者是指针。
i = s
i.sayhi()
t := &Teacher{"hc", "www"}
i = t
i.sayhi()
var m MyStr = "hc"
//m := "hc" // 这样写的话,会导致i = &m错误,因为自动推导类型会是string,而不是MyStr,
//所以不会存在sayhi方法。即使MyStr就是string类型,但是编译器认为MyStr与string是不同的类型。
i = &m
i.sayhi()
}
3 多态的表现
多态就是同样的接口可以表现出多种形态。
package main
import "fmt"
// 接口的定义
type Humaner interface {
// 方法,只有声明,没有实现,由别的类型去实现
sayhi()
}
type Student struct {
name string
id int
}
func (t *Student) sayhi(){
fmt.Printf("Student[%s, %d], sayhi\n", t.name, t.id)
}
type Teacher struct {
addr string
group string
}
func (t *Teacher) sayhi(){
fmt.Printf("Teacher[%s, %s], sayhi\n", t.addr, t.group)
}
type MyStr string
func (t *MyStr) sayhi(){
fmt.Printf("MyStr[%s], sayhi\n", *t)
}
// 定义一个普通函数,形参为接口类型,
// 这样可以使一个函数,但是有不同的行为,即多态
func WhoSayHi(i Humaner){
i.sayhi()
}
func main(){
s := &Student{"hc", 1}
t := &Teacher{"hc", "www"}
var m MyStr = "hc"
WhoSayHi(s)
WhoSayHi(t)
WhoSayHi(&m)
// 或者可以这样写
arr := make([]Humaner, 3)
arr[0] = s
arr[1] = t
arr[2] = &m
for _, v := range arr{
v.sayhi()
}
}
4 接口的继承
package main
import "fmt"
// 接口的定义
// 子集,相当于基类
type Humaner interface {
// 方法,只有声明,没有实现,由别的类型去实现
sayhi()
}
// 超集,相当于派生类
type Persioner interface {
Humaner // 匿名字段,继承接口,所以上面的sayhi方法也会有
sing(t string)
}
type Student struct {
name string
id int
}
func (t *Student) sayhi(){
fmt.Printf("Student[%s, %d], sayhi\n", t.name, t.id)
}
func (t *Student) sing(s string){
fmt.Printf("Student sing %s\n", s)
}
func main(){
// 1. 定义该接口变量,值由实现了 该接口中的方法 的类型赋值
var i Persioner
s := &Student{"hc", 1} // 为指针是因为接口实现的方法的接收者是指针。
i = s
i.sayhi()
i.sing("lqq")
}
5 接口的转换
接口的转换就是超集与子集的转换而已,超集指继承后的接口,子集指被继承的接口。对比C++,子集等价于基类,超集等价于派生类。所以有:
- 1)超集可以转成子集,而子集不能转成超集。学过C++的知道,这是因为子集转超集时会导致地址越界,无法寻址到对应的内存。
package main
import "fmt"
// 接口的定义
// 子集,相当于基类
type Humaner interface {
// 方法,只有声明,没有实现,由别的类型去实现
sayhi()
}
// 超集,相当于派生类
type Persioner interface {
Humaner // 匿名字段,继承接口,所以上面的sayhi方法也会有
sing(t string)
}
type Student struct {
name string
id int
}
func (t *Student) sayhi(){
fmt.Printf("Student[%s, %d], sayhi\n", t.name, t.id)
}
func (t *Student) sing(s string){
fmt.Printf("Student sing %s\n", s)
}
func main(){
// 超集可以转成子集,而子集不能转成超集。
var iPro Persioner // 超集
iPro = &Student{"hc", 1}
var i Humaner // 子集
i = iPro // ok
i.sayhi()
//iPro = i // err:cannot use i (type Humaner) as type Persioner in assignment:
// Humaner does not implement Persioner (missing sing method)
}
6 空接口
- 1)空接口(interface{})不包含任何方法,正因为如此,所以任何类型都实现了空接口。因为空接口可以存储任意类型的赋值,类似C/C++的void*。
var i interface{} = 1
fmt.Printf("i = %d\n", i)
i = "abc"
fmt.Printf("i = %s\n", i)
- 2)当函数想要接收任意类型的参数,那么可以将形参定义为空接口。最典型的就是标准库fmt的Printxxx类函数。例如简单列出两个:
func Println(a ...interface{}) (n int, err error)
func Printf(format string, a ...interface{}) (n int, err error)
7 类型查询(也叫类型断言)
下面通过两种方法去实现。
- 1)通过if实现类型查询。
- 2)通过switch实现类型查询。
package main
import (
"fmt"
)
// 接口的定义
// 子集,相当于基类
type Humaner interface {
// 方法,只有声明,没有实现,由别的类型去实现
sayhi()
}
// 超集,相当于派生类
type Persioner interface {
Humaner // 匿名字段,继承接口,所以上面的sayhi方法也会有
sing(t string)
}
type Student struct {
name string
id int
}
func (t *Student) sayhi(){
fmt.Printf("Student[%s, %d], sayhi\n", t.name, t.id)
}
func (t *Student) sing(s string){
fmt.Printf("Student sing %s\n", s)
}
func main(){
i := make([]interface{}, 3)
i[0] = 1
i[1] = "hhh"
i[2] = Student{"hc", 1}
// 类型查询(类型断言)
// 1. if实现
for k, v := range i{
if value, ok := v.(int); ok == true {
fmt.Printf("x[%d], 类型为int,内容为: %d\n", k, value)
}else if value, ok := v.(string); ok == true{
fmt.Printf("x[%d], 类型为string,内容为: %s\n", k, value)
}else if value, ok := v.(Student); ok == true{
fmt.Printf("x[%d], 类型为Student,内容为: name=%s, id=%d\n", k, value.name, value.id)
}
}
// 2. switch实现
for k, v := range i{
switch value := v.(type) {
case int:
fmt.Printf("x[%d], 类型为int,内容为: %d\n", k, value)
case string:
fmt.Printf("x[%d], 类型为string,内容为: %s\n", k, value)
case Student:
fmt.Printf("x[%d], 类型为Student,内容为: name=%s, id=%d\n", k, value.name, value.id)
}
}
}