【原创】go语言学习(十六)接口
目录
- 接口介绍与定义
- 空接口和类型断言
- 指针接收和值接收区别
- 接口嵌套
接口介绍与定义
1、 接口定义了一个对象的行为规范
A. 只定义规范,不实现
B. 具体的对象需要实现规范的细节
2、Go中接口定义
A. type 接口名字 interface
B. 接口里面是一组方法签名的集合
type Animal interface { Talk() Eat() int Run() }
3、Go中接口的实现
A. 一个对象只要包含接口中的方法,那么就实现了这个接口
B. 接口类型的变量可以保存具体类型的实例
type Animal interface { Talk() Eat() int Run() }
4、接口实例
A. 一个公司需要计算所有职员的薪水
B. 每个职员的薪水计算方式不同
package main import ( "fmt" ) type Employer interface { CalcSalary() float32 } type Programer struct { name string base float32 extra float32 } func NewProgramer(name string, base float32, extra float32) Programer { return Programer{ name: name, base: base, extra: extra, } } func (p Programer) CalcSalary() float32 { return p.base } type Sale struct { name string base float32 extra float32 } func NewSale(name string, base, extra float32) Sale { return Sale{ name: name, base: base, extra: extra, } } func (p Sale) CalcSalary() float32 { return p.base + p.extra*p.base*0.5 } func calcALL(e []Employer) float32 { var cost float32 for _, v := range e { cost = cost + v.CalcSalary() } return cost } func main() { p1 := NewProgramer("搬砖1", 1500.0, 0) p2 := NewProgramer("搬砖2", 1500.0, 0) p3 := NewProgramer("搬砖3", 1500.0, 0) s1 := NewSale("销售1", 800.0, 2.5) s2 := NewSale("销售2", 800.0, 2.5) s3 := NewSale("销售3", 800.0, 2.5) var employList []Employer employList = append(employList, p1) employList = append(employList, p2) employList = append(employList, p3) employList = append(employList, s1) employList = append(employList, s2) employList = append(employList, s3) cost := calcALL(employList) fmt.Printf("这个月的人力成本:%f\n", cost) }
5、接口类型变量
A. var a Animal
B. 那么a能够存储所有实现Animal接口的对象实例
package main import "fmt" type Animal interface { Talk() Eat() Name() string } type Dog struct { } func (d Dog) Talk() { fmt.Println("汪汪汪") } func (d Dog) Eat() { fmt.Println("我在吃骨头") } func (d Dog) Name() string { fmt.Println("我的名字叫旺财") return "旺财" } type Pig struct { } func (d Pig) Talk() { fmt.Println("坑坑坑") } func (d Pig) Eat() { fmt.Println("我在吃草") } func (d Pig) Name() string { fmt.Println("我的名字叫八戒") return "八戒" } func testInterface1() { var d Dog var a Animal a = d a.Eat() a.Talk() a.Name() var pig Pig a = pig a.Eat() a.Talk() a.Name() } func just(a Animal) { // d, ok := a.(Dog) // p, ok := a.(Pig) switch v := a.(type) { case Dog: fmt.Printf("v is dog, %v\n", v) case Pig: fmt.Printf("v is dog, %v\n", v) default: fmt.Printf("not support") } } func testInterface2() { var d Dog just(d) } func main() { //testInterface1() testInterface2() }
空接口和类型断言
1、空接口
A. 空接口没有定义任何方法
B. 所以任何类型都实现了空接口
interface { }
package main import "fmt" func describe(a interface{}) { fmt.Printf("%T %v\n", a, a) } func testInterface() { var a interface{} var b int = 100 a = b fmt.Printf("%T %v\n", a, a) var c string = "hello" a = c fmt.Printf("%T %v\n", a, a) var d map[string]int = make(map[string]int, 100) d["abc"] = 1000 d["eke"] = 30 a = d fmt.Printf("%T %v\n", a, a) } type Student struct { Name string Sex int } func main() { a := 65 describe(a) str := "hello" describe(str) var stu Student = Student{ Name: "user01", Sex: 1, } describe(stu) }
2、类型断言
A. 如何获取接口类型里面存储的具体的值呢?
B.类型断言的坑
C.如何解决,引入 ok判断机制! v, ok := i.(T)
D.type switch。
E.type switch另外一种写法,解决转两次的问题
package main import "fmt" // 类型断言 func test(a interface{}) { s, ok := a.(int) if ok { fmt.Println(s) return } str, ok := a.(string) if ok { fmt.Println(str) return } f, ok := a.(float32) if ok { fmt.Println(f) return } fmt.Println("can not define the type of a") } func testInterface1() { var a int = 100 test(a) var b string = "hello" test(b) } // case优雅实现(二次转换) func testSwitch(a interface{}) { switch a.(type) { case string: fmt.Printf("a is string, value: %v", a.(string)) case int: fmt.Printf("a is int, value: %v", a.(int)) case int32: fmt.Printf("a is not, value: %v", a.(int32)) default: fmt.Println("no support type") } } func testInterface2() { var a int = 100 testSwitch(a) var b string = "hellow" testSwitch(b) } // case优雅实现(一次转换) func testSwitch2(a interface{}) { switch v := a.(type) { case string: fmt.Printf("a is string, value: %v", v) case int: fmt.Printf("a is int, value: %v", v) case int32: fmt.Printf("a is not, value: %v", v) default: fmt.Println("no support type") } } func testInterface3() { var a int = 100 testSwitch2(a) var b string = "hellow" testSwitch2(b) } func main() { testInterface1() testInterface2() testInterface3() }
指针接收和值接收区别
1、指针接收
package main import "fmt" type Animal interface { Talk() Eat() Name() string } type Dog struct { } func (d *Dog) Talk() { fmt.Println("汪汪汪") } func (d *Dog) Eat() { fmt.Println("我在吃骨头") } func (d *Dog) Name() string { fmt.Println("我的名字叫旺财") } func main() { var a Animal // 值 // a存的是一个值类型的Dog,那么调用a.Eat(). &Dog ->Eat() // 如果一个变量存储在接口类型的变量中之后,那么不能获取这个变量的地址 //var d Dog //a = d //a.Eat() // //fmt.Printf("%T %v\n", a, a) // 指针 var d1 *Dog = &Dog{} a = d1 // *(&Dog).Eat() a.Eat() fmt.Printf("*Dog %T %v\n", d1, d1) }
接口嵌套
1、 实现多接口,同一个类型可以实现多个接口
2、 接口嵌套,和结构体嵌套类似
package main import "fmt" type Animal interface { Talk() Eat() Name() string } type PuruDongwu interface { TaiSheng() } type Dog struct { } func (d Dog) Talk() { fmt.Println("汪汪汪") } func (d Dog) Eat() { fmt.Println("我在吃骨头") } func (d Dog) Name() string { fmt.Println("我的名字叫旺财") return "旺财" } func (d Dog) TaiSheng() { fmt.Println("狗是胎生的") } func main() { var d Dog var a Animal fmt.Printf("%v %T %p", a, a, a) if a == nil { fmt.Println("a is nil") } a = d a.Eat() var b PuruDongwu b = d b.TaiSheng() }