Go接口

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\n",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...\n", food)
//}

// 使用指针接收者实现了接口的所有方法
func (c *cat) move() {
	fmt.Println("走猫步...")
}
func (c *cat) eat(food string) {
	fmt.Printf("猫吃%s...\n", 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\n",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\n",ins,&ins,ins)
		fmt.Printf("s:%T,%p,%p\n",s,&s,s)
	}else {
		fmt.Println("我也不知道了。。。")

	}
}

//定义一个函数
func testShape(s Shape){ //参数是接口类型
	fmt.Printf("周长:%.2f,面积:%.2f\n",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
}

  

posted @ 2020-02-01 09:13  1769987233  阅读(127)  评论(0)    收藏  举报