1. 实现接口
接口的作用就是对外隐藏实现。
Golang 中没有 class 的概念,而是通过 interface 类型转换支持在动态类型语言中常见的鸭子类型
从而达到运行时多态的效果。
简而言之,interface就是一组method的集合。 只要一个类型A实现了接口I中的method,那么在之后的使用时,这个接口I类型的变量便可以接受类型A的变量。这样在之后的使用中,同一个接口,可以接收不同类型的变量。
interface的变量可以持有任意实现该interface类型的对象。
package main import "fmt" /* 接口是一种类型,是一种特殊的类型,它规定了变量有哪些方法 在编程中会遇到以下场景: 我不关心一个变量是什么类型,我只关心能调用它的什么方法 比如不管你是支付宝还是微信还是银联,都能调用这个支付方法; 不管你是三角形还是正方形,都能调用计算面积这个方法; 不管你是行政销程序员都能调用计算工资的方法。 */ // 引出接口的实例 // 定义一个能叫的类型 type speaker interface { speak() // 只要实现了speak方法的变量都是speaker类型, 方法签名 } type cat struct{} type dog struct{} type person struct{} func (c cat) speak() { fmt.Println("喵喵喵~") } func (d dog) speak() { fmt.Println("旺旺旺~") } func (p person) speak() { fmt.Println("啊啊啊~") } func da(x speaker) { // 接收一个参数,传进来什么,我就打什么 x.speak() // 挨打了就要叫 } func main() { var c1 cat var d1 dog var p1 person da(c1) da(d1) da(p1) var ss speaker // 定义一个接口类型:speaker 的变量:ss ss = c1 ss = d1 ss = p1 fmt.Println(ss) }
package main import "fmt" func main() { /* 接口:interface 1. 在Go中,接口是一组方法签名。当类型为接口中的所有方法提供定义时,它被称为实现接口。它与OOP非常相似。 接口指定了类型应该具有的方法,类型决定了如何实现这些方法。 2. 它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。 3. 接口定义了一组方法,如果某个对象实现了某个接口的所有方法,则此对象就实现了该接口。 Go语言中,接口和实现类的关系,是非侵入式 //其他语言中,要显示的定义 class Mouse implements USB{} 1.当需要接口类型的对象时,可以使用任意实现类对象代替 2.接口对象不能访问实现类中的属性,赋值给一个变量(实例对象)是可以访问的 多态:一个事物的多种形态 go语言通过接口模拟多态 就一个接口的实现 1.看成实现本身的类型,能够访问实现类中的属性和方法 2.看成是对应的接口类型,那就只能够访问接口中的方法(其他语言中就是只能访问父类的方法) 接口的用法: 1.一个函数如果接受接口类型作为参数,那么实际上可以传入该接口的任意实现类型对象作为参数。 2.定义一个类型为接口类型,实际上可以赋值为任意实现类的对象 鸭子类型:针对动态类型语言来说的(Python),长得像鸭子,走起路来像鸭子,叫起来像鸭子,那么它就是鸭子 1. 是一种类型推断策略 2. 关注的是对象如何被使用,而不是对象本身的类型 3. Go不要求显示显示声明实现了那个接口,接口的实现只要实现了方法就可以,Go也支持鸭子模型 */ //1.创建Mouse类型 m1 := Mouse{"罗技小红"} fmt.Println(m1.name) //2.创建FlashDisk f1 := FlashDisk{"闪迪64G"} fmt.Println(f1.name) testInterface(m1) //参数是USB接口类型对象 testInterface(f1) var usb USB usb= f1 usb.start() usb.end() //fmt.Println(usb.name) f1.deleteData() //usb.de var arr [3]USB arr[0] = m1 arr[1] = f1 fmt.Println(arr) } //1.定义接口 type USB interface { start() //USB设备开始工作 end() //USB设备结束工作 } //2.实现类 type Mouse struct { name string } type FlashDisk struct { name string } func (m Mouse)start(){ fmt.Println(m.name,"鼠标,准备就绪,可以开始工作了,点点点。。") } func (m Mouse) end(){ fmt.Println(m.name,"结束工作,可以安全退出。。") } func (f FlashDisk)start(){ fmt.Println(f.name,"准备开始工作,可以进行数据的存储。。") } func (f FlashDisk)end(){ fmt.Println(f.name,"可以弹出。。") } func (f FlashDisk) deleteData(){ fmt.Println(f.name,"U盘删除数据。。") } //3.测试方法 func testInterface(usb USB){ //usb = m1 usb = f1 usb.start() usb.end() }
2. 多态
3. 空接口
package main import "fmt" func main() { /* 空接口(interface{}) 不包含任何的方法,正因为如此,所有的类型都实现了空接口,因此空接口可以存储任意类型的数值。 空接口是指没有定义任何方法的接口。因此任何类型都实现了空接口。 空接口类型的变量可以存储任意类型的变量。 fmt包下的Print系列函数的参数就有空接口: //接收可变参数,任意类型 func Print(a ...interface{}) (n int, err error) func Printf(format string, a ...interface{}) (n int, err error) func Println(a ...interface{}) (n int, err error) */ var a1 A = Cat{"花猫"} var a2 A = Person{"王二狗",30} var a3 A = "haha" var a4 A = 100 fmt.Println(a1) fmt.Println(a2) fmt.Println(a3) fmt.Println(a4) test1(a1) test1(a2) test1(3.14) test1("Ruby") test2(a3) test2(1000) //map,key字符串,value任意类型 map1 := make(map[string]interface{}) map1["name"] = "李小花" map1["age"] = 30 map1["friend"] = Person{"Jerry",18} fmt.Println(map1) //切片,存储任意类型的数据 slice1 := make([]interface{},0,10) slice1 = append(slice1,a1,a2,a3,a4,100,"abc") fmt.Println(slice1) test3(slice1) } func test3(slice2 []interface{}){ for i:=0;i<len(slice2);i++{ fmt.Printf("第%d个数据:%v ",i+1,slice2[i]) } } //接口A是空接口,理解为代表了任意类型 func test1(a A){ //这个空接口是有名字的 fmt.Println(a) } func test2(a interface{}){ fmt.Println("--->",a) } //空接口 type A interface { } type Cat struct { color string } type Person struct { name string age int }
4. 值接收者和指针接收者实现结构
package main import "fmt" // 使用值接收者和指针接收者的区别? //使用值接收者实现接口,结构体类型和结构体指针类型的变量都能存 //指针接收者实现接口只能存结构体指针类型的变量 type animal interface { move() eat(string) } type cat struct { name string feet int8 } // 使用值接收者实现了接口的所有方法 //func (c cat) move() { // fmt.Println("走猫步...") //} //func (c cat) eat(food string) { // fmt.Printf("猫吃%s... ", food) //} // 使用指针接收者实现了接口的所有方法 func (c *cat) move() { fmt.Println("走猫步...") } func (c *cat) eat(food string) { fmt.Printf("猫吃%s... ", food) } func main() { var a1 animal c1 := cat{"tom", 4} // cat c2 := &cat{"假老练", 4} // *cat a1 = &c1 //实现animal这个接口的是cat的指针类型 //指针类型的变量实现了该接口,该变量就是该接口(animal)类型 //所以该变量可以赋值给接口变量 fmt.Println(a1) a1 = c2 fmt.Println(a1) }
5. 接口的嵌套
package main import "fmt" func main() { /* 接口的嵌套: */ var cat Cat = Cat{} cat.test1() cat.test2() cat.test3() //a1是A接口类型,里面只有test1() var a1 A = cat a1.test1() //b1是A接口类型,里面只有test2() var b1 B = cat b1.test2() //把cat看做是接口C,那么就可以访问test1(),test2(),test3() //接口C的实现肯定也实现了接口A和接口B中的方法 var c1 C = cat c1.test1() c1.test2() c1.test3() //接口A的实现是没有实现接口C中的方法的,接口C中有更多的功能 //var c2 C = a1 //错误的写法 //这样就没有问题,但是就只能调用test1()方法了 var a2 A = c1 a2.test1() } type A interface { test1() } type B interface { test2() } type C interface { A B test3() } type Cat struct { //如果想实现接口C,那不止要实现接口C的方法,还要实现接口A,B中的方法 } func (c Cat) test1() { fmt.Println("test1()....") } func (c Cat) test2() { fmt.Println("test2()....") } func (c Cat) test3() { fmt.Println("test3()....") }
6. 接口断言
package main import ( "math" "fmt" ) func main() { /* 接口断言: 方式一: 1.instance := 接口对象.(实际类型) //不安全,会panic() 2.instance, ok := 接口对象.(实际类型) //安全 方式二:switch switch instance := 接口对象.(type){ case 实际类型1: .... case 实际类型2: .... .... } */ //三角形 var t1 Triangle = Triangle{3,4,5} fmt.Println(t1.peri()) fmt.Println(t1.area()) fmt.Println(t1.a, t1.b,t1.c) //圆形 var c1 Circle = Circle{4} fmt.Println(c1.peri()) fmt.Println(c1.area()) fmt.Println(c1.radius) //定义一个接口类型 var s1 Shape s1 = t1 fmt.Println(s1.peri()) fmt.Println(s1.area()) //定义一个接口类型 var s2 Shape s2 = c1 fmt.Println(s2.peri()) fmt.Println(s2.area()) testShape(t1) testShape(c1) testShape(s1) getType(t1) getType(c1) getType(s1) //getType(100) //指针类型 var t2 *Triangle = &Triangle{3,4,2} fmt.Printf("t2:%T,%p,%p ",t2,&t2,t2) getType(t2) getType2(t2) getType2(t1) } //断言,使用switch func getType2 (s Shape){ switch ins := s.(type) { case Triangle: fmt.Println("三角形。。",ins.a,ins.b,ins.c) case Circle: fmt.Println("圆形。。",ins.radius) case *Triangle: fmt.Println("三角形结构体指针:",ins.a,ins.b,ins.c) } } //断言,使用if func getType(s Shape){ //接口类型的变量 //判断这个s是不是三角形 if ins, ok := s.(Triangle) ; ok{ //如果ok为true fmt.Println("是三角形,三边是:",ins.a,ins.b,ins.c) }else if ins, ok := s.(Circle); ok{ fmt.Println("是圆形,半径是:",ins.radius) }else if ins, ok := s.(*Triangle) ;ok{ fmt.Printf("ins:%T,%p,%p ",ins,&ins,ins) fmt.Printf("s:%T,%p,%p ",s,&s,s) }else { fmt.Println("我也不知道了。。。") } } //定义一个函数 func testShape(s Shape){ //参数是接口类型 fmt.Printf("周长:%.2f,面积:%.2f ",s.peri(),s.area()) } //1.定义一个接口 type Shape interface { peri() float64 //形状的周长 area() float64 //形状的面积 } //2.定义实现类:三角形 type Triangle struct { //a float64 //b float64 //c float64 a, b, c float64 //简写 } func (t Triangle) peri() float64 { return t.a + t.b + t.c } func (t Triangle) area() float64 { p := t.peri() / 2 s := math.Sqrt(p * (p-t.a)*(p-t.b)*(p-t.c)) //开平方 return s } type Circle struct { radius float64 } func (c Circle) peri()float64 { return c.radius * 2 * math.Pi } func (c Circle) area () float64{ return math.Pow(c.radius,2) * math.Pi }