继承 继承实现方法 在Go中,继承采用匿名结构体 实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 type Student struct { Name string Age int } type Graduate struct { Student id int } type PostGraduates struct { Student Tutor string }
继承的细节
结构体和嵌入的匿名结构体中,有相同的字段和方法时,编译器采用就近原则 。要访问匿名结构体的字段时,加上匿名结构体来区分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 type A struct { Name string } type B struct { A Name string } func main () { var b B b.A.Name = "marry" fmt.Println(b.Name) fmt.Println(b.A.Name) b.Name = "smith" fmt.Println(b.Name) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 type Person struct { Name string Age int } type Info struct { Id int Score int } type Student struct { *Person *Info } func main () { stu := Student{ &Person{"john" , 18 }, &Info{001 , 90 }, } }
嵌入多个匿名结构体,可以实现多重继承。因为多重继承使得继承关系混乱,所以并不推荐多重继承
接口 若多个类型都有一个或者多个共同点,那么就可以将这些共同的抽象出来聚合在一起,形成接口。接口与现实中的接口类似,如USB接口,USB接口可以插入手机、鼠标、键盘等设备,只要符合USB标准即可。
接口实现了高内聚,低耦合 的思想
接口实现方法 Go中的接口,不需要显式的实现 。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现了这个接口。一般定义方法如下:
1 2 3 4 5 type InterfaceName interface { }
下面抽象的定义一个USB接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 type Usb interface { Work() Stop() } type Phone struct { } func (p Phone) Work () { } func (p Phone) Stop () { } type Mouse struct { } func (m Mouse) Work () { } func (m Mouse) Stop () { } type Computer struct { } func (c Computer) Working (usb Usb) { usb.Start() if phone, ok := usb.(Phone); ok { } usb.Stop() } func main () { computer := Computer{} phone := Phone{} mouse := Mouse{} computer.Working(phone) computer.Working(mouse) }
接口的细节
接口的实现 是指,一个类型实现了被定义接口内的所有方法 (隐式实现)。一个自定类型可以实现多个接口
接口不能创建变量,但可以指向 一个实现了该接口 的自定义类型(不仅仅是结构体 )的实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 type A interface { test() } type Student struct { Name string } func (stu Student) test () { fmt.Println("Stu test()" ) } func main () { var stu Student var a A = stu a.test() }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 type B interface { test1() } type C interface { test2() } type A interface { B C test3() } type Student struct { Name string } func (stu Student) test1 () { } func (stu Student) test2 () { } func (stu Student) test3 () { }
interface是引用类型 (指针)
空接口interface{}没有实现任何方法,所以所有类型都实现了空接口,可以把任何变量都赋值给空接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 type T interface { } func main () { num1 := 6.17 num2 := 6 var t1 T = num1 fmt.Println(t1) var t2 interface {} = num2 fmt.Println(t2) }
实践:实现Interface接口,对结构体切片进行排序 一个满足sort.Interface
接口的(集合)类型可以被本包的函数进行排序。
1 2 3 4 5 6 7 8 type Interface interface { Len() int Less(i, j int ) bool Swap(i, j int ) }
以Hero结构体实现Interface接口,对Hero的年龄进行排序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 package mainimport ( "fmt" "math/rand" "sort" ) type Hero struct { Name string Age int } type HeroSlice []Herofunc (hs HeroSlice) Len () int { return len (hs) } func (hs HeroSlice) Less (i, j int ) bool { return hs[i].Age < hs[j].Age } func (hs HeroSlice) Swap (i, j int ) { hs[i], hs[j] = hs[j], hs[i] } func main () { var heroes HeroSlice for i := 0 ; i < 5 ; i++ { hero := Hero{ Name: fmt.Sprintf("英雄-%d" , rand.Intn(100 )), Age: rand.Intn(150 ), } heroes = append (heroes, hero) } fmt.Println("========排序前========" ) for _, v := range heroes { fmt.Println(v) } sort.Sort(heroes) fmt.Println("========排序后========" ) for _, v := range heroes { fmt.Println(v) } }
接口和继承的关系
接口的实现可以看作对继承的补充
接口和继承的解决问题不同:
继承 :解决代码复用性 和可维护性
接口 :设计 ,设计和各种规范(方法),让其他自定义类型去实现这些方法
接口比继承更灵活 :
继承是is-a的关系
接口只需满足like-a的关系
接口在一定程度上实现了代码的解耦
多态 在GO中,多态是通过接口实现的 。可以安装统一的接口调用不同的实现,这是接口变量就程序不同的形态。
接口体现多态 2种形式如下:
多态参数 :以接口作为函数的参数
多态数组 :接口数组可以存放任何实现了该接口的变量
类型断言 使用方法 由于接口是一般类型,不知道具体类型,若要从接口转换成具体类型 ,就需要类型断言
1 2 3 4 5 6 7 8 9 10 11 12 13 var z float32 = 1.1 var x interface {} x = z y, ok := x.(float32 ) if ok { } else { }