26、接口

发布时间 2023-09-28 01:15:59作者: 我也有梦想呀

1、是什么?

  • 面向对象世界中的接口的一般定义是”接口定义对象的行为”。它表示让指定对象应该做什么。实现这种行为的方法(实现细节)是针对对象的。

  • 在Go中,接口是一组方法签名。当类型为接口中的所有方法提供定义时,它被称为实现接口。它与0OP非常相似。接口指定了类型应该具有的方法,类型决定了如何实现这些方法。

它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口

接口定义了一组方法,如果某个对象实现了某个接口的所有方法,则此对象就实现了该接口。

2、语法

Java语言中的接口

interface UserService{}
class UserServiceImpl implements UserService{}

1.当需要接口类型的对象时,可以使用任意实现类对象代替
2.接口对象不能访问实现类中的属性

多态:一个事物的多种形态
go语言通过接口模拟多态
就一个接口的实现

  • 1.看成实现本身的类型,能够访问实现类中的属性和方法
  • 2.看成是对应的接口类型,那就只能够访问接口中的方法
    接口的用法:
  • 1.一个函数如果接受接口类型作为参数,那么实际上可以传入该接口的任意实现类型对象作为参数
  • 2.定义一个类型为接口类型,实际上可以赋值为任意实现类的对象
/**
 * @author ly (个人博客:https://www.cnblogs.com/ybbit)
 * @date 2023/9/27  21:04
 * @tags 喜欢就去努力的争取
 */
package main

import "fmt"

func main() {

	m := Mouse{name: "雷蛇"}
	m.start()
	m.end()

	f := FlashDisk{name: "金士顿"}
	f.start()
	f.end()

	m2 := Mouse{name: "达尔优"}
	testInterface(m2)

	f2 := FlashDisk{name: "西部数码"}
	testInterface(f2)
	f2.deleteData()

	var usb USB

	usb = Mouse{name: "罗技"}
	usb.start()
	usb.end()

	usb = FlashDisk{name: "迪特"}
	usb.start()
	usb.end()
	// usb.deleteData()

	arr := [3]USB{}
	arr[0] = m2
	arr[1] = f2
	arr[2] = f

}

type USB interface {
	start() // 开始工作
	end()   // 结束工作
}

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, "U盘,准备就绪,可以开始进行数据存储...")
}

func (f FlashDisk) end() {
	fmt.Println(f.name, "数据传输结束,可以安全拔出...")
}

// 测试方法
func testInterface(usb USB) {
	usb.start()
	usb.end()
}

func (f FlashDisk) deleteData() {
	fmt.Println(f.name, " U盘 ,删除数据")
}

3、空接口

/**
 * @author ly (个人博客:https://www.cnblogs.com/ybbit)
 * @date 2023/9/27  21:34
 * @tags 喜欢就去努力的争取
 */
package main

import "fmt"

func main() {

	var a1 A = Cat{color: "小黄"}

	var a2 A = Person{name: "张三", age: 20}

	var a3 A = [2]int{}
	var a4 A = []int{}
	var a5 A = make(map[int]string, 3)
	var a6 A = "hello GO"
	var a7 A = 100
	var a8 A = &a1
	var a9 A = [1]*int{}
	fmt.Printf("%T \n", a1)
	fmt.Printf("%T \n", a2)
	fmt.Printf("%T \n", a3)
	fmt.Printf("%T \n", a4)
	fmt.Printf("%T \n", a5)
	fmt.Printf("%T \n", a6)
	fmt.Printf("%T \n", a7)
	fmt.Printf("%T \n", a8)
	fmt.Printf("%T \n", a9)

	printA(a1)
	printA(a2)
	printA(a3)
	printA(a4)
	printA(a5)
	printA(a6)
	printA(a7)

	printB(a1)
	printB(a2)
	printB(a3)
	printB(100)
	printB("hello GO")

	map1 := make(map[string]interface{})
	map1["1"] = "1"
	map1["2"] = 2
	map1["3"] = 3.3
	map1["4"] = true
	map1["5"] = a1
	map1["6"] = a2
	map1["7"] = a3
	map1["8"] = a5

	fmt.Println(map1)

	slice1 := make([]interface{}, 0, 10)
	slice1 = append(slice1, "hello", 100, 100.99, true, a1, a2, a3, a5)
	slice1[3] = "你好"
	fmt.Println(slice1)

	printInterface(slice1)
	// printInterface(map1)

}

func printInterface(arr []interface{}) {
	fmt.Println(cap(arr))
	for i := 0; i < len(arr); i++ {
		fmt.Printf("%T,%v \t", arr[i], arr[i])
	}
	fmt.Println()
}

type A interface {
}

type Cat struct {
	color string
}

type Person struct {
	name string
	age  int
}

func printA(a A) {
	fmt.Println(a)
}

// 匿名空接口
func printB(b interface{}) {
	fmt.Println(b)
}

4、接口嵌套

这就有点类似Java语言中的接口可以继承多个接口

interface A {
test1()
}

interface B {
test2()
}

interface C extends A,B{
test3()
}

/**
 * @author ly (个人博客:https://www.cnblogs.com/ybbit)
 * @date 2023/9/27  22:45
 * @tags 喜欢就去努力的争取
 */
package main

import "fmt"

func main() {

	var c1 Cat = Cat{name: "Tom"}
	c1.test1()
	c1.test2()
	c1.test3()

	var a1 A = Cat{}
	a1.test1()

	var b1 B = Cat{}
	b1.test2()

	var c2 C = Cat{}
	c2.test1()
	c2.test2()
	c2.test3()

	// var c3 C = a1 // 不能吧A类型赋值给C类型

	var a2 A = c2 // 可以把C类型赋值给A类型
	a2.test1()

}

type A interface {
	test1()
}

type B interface {
	test2()
}

type C interface { // 实现C接口,不仅要实现C接口的方法,还要实现A、B接口的方法
	A
	B
	test3()
}

type Cat struct {
	name string
}

func (c Cat) test1() {
	fmt.Println("test1...")
}

func (c Cat) test2() {
	fmt.Println("test2...")
}

func (c Cat) test3() {
	fmt.Println("test3...")
}

5、接口断言

前面说过,因为空接口interface{}没有定义任何函数,因此Go 中所有类型都实现了空接口。当一个函数的形参是interface{},那么在函数中,需要对形参进行断言,从而得到它的真实类型。

// 安全类型断言
<目标类型的值>,<布尔类型> := <表达式>,(目标类型)

// 非安全类型断言
<目标类型的值> := <表达式>,(目标类型)

方式一:
	1、instance := 接口对象.(实际类型) // 不安全,会出现panic()
	2、instance,ok := 接口对象.(实际类型) // 不安全,会出现panic()
方式二: switch
	switch instance := 接口对象.(type){
	case 实际类型1:
		...
	case 实际类型2:
		...

	......
	}

示例

/**
 * @author ly (个人博客:https://www.cnblogs.com/ybbit)
 * @date 2023/9/28  0:20
 * @tags 喜欢就去努力的争取
 */
package main

import (
	"fmt"
	"math"
)

func main() {

	/*
		接口断言:
			方式一:
				1、instance := 接口对象.(实际类型) // 不安全,会出现panic()
				2、instance,ok := 接口对象.(实际类型) // 不安全,会出现panic()
			方式二: switch
				switch instance := 接口对象.(type){
				case 实际类型1:
					...
				case 实际类型2:
					...

				......
				}

	*/

	// 长方形
	t1 := Triangle{a: 30, b: 40, c: 50}
	fmt.Printf("变长a:%.2f,b:%.2f,c:%.2f \t 周长C:%.2f \t 面积S:%.2f \n", t1.a, t1.b, t1.c, t1.area(), t1.peri())

	// 圆形
	c1 := Circle{radius: 8}
	fmt.Printf("半径r:%.2f \t 周长C:%.2f \t 面积S:%.2f \n", c1.radius, c1.area(), c1.peri())

	var s1 Shape // 定义接口,接口不可以访问实现类的属性
	s1 = t1
	s1.peri()
	s1.area()

	var s2 Shape
	s2 = c1
	s2.peri()
	s2.area()

	// testShape(t1)
	// testShape(c1)
	// testShape(s1)
	// testShape(s2)

	/*map1 := make(map[int]string)
	value, ok := map1[1]
	if ok {
		fmt.Println(value)
	} else {
		fmt.Println("key不存在")
	}*/

	// getType(t1)
	// getType(c1)

	// 结构体是一个值传递类型,所以他会把值copy一份
	var t2 *Triangle = &Triangle{3, 5, 6}
	fmt.Printf("%T,%p,%p\n", t2, &t2, t2)
	// getType(t2)

	// switch
	getType2(t2)
}

func getType2(s Shape) {
	switch instance := s.(type) {
	case Triangle:
		fmt.Println("是三角形实例", instance, instance.a, instance.b, instance.c, instance.area(), instance.peri())
	case Circle:
		fmt.Println("是圆形", instance.radius, instance.area(), instance.peri())
	case *Triangle:
		fmt.Printf("%T,%p,%p\n", instance, &instance, instance)
		fmt.Printf("%T,%p,%p\b", s, &s, s)
	default:
		fmt.Println("不知道什么类型")
	}
}

// 断言类型
func getType(s Shape) {
	// 断言类型中instance,会被重新创建为一个新的对象
	if instance, ok := s.(Triangle); ok {
		fmt.Println("是三角形实例", instance, instance.a, instance.b, instance.c, instance.area(), instance.peri())
	} else if instance, ok := s.(Circle); ok {
		fmt.Println("是圆形", instance.radius, instance.area(), instance.peri())
	} else if instance, ok := s.(*Triangle); ok {
		fmt.Printf("ins:%T,%p,%p\n", instance, &instance, instance)
		fmt.Printf("s:%T,%p,%p\n", s, &s, s)
	} else {
		// panic("不知道什么类型")
		fmt.Println("不知道什么类型")
	}
}

func testShape(s Shape) {
	fmt.Printf("周长:%.2f,\t 面积%.2f \n", s.area(), s.peri())
}

type Shape interface {
	peri() float64
	area() float64
}

type Triangle struct {
	a, b, c float64
}

func (t Triangle) area() float64 {
	return t.a + t.b + t.c
}

func (t Triangle) peri() float64 {
	p := t.area() / 2
	s := math.Sqrt(p * (p - t.a) * (p - t.b) * (p - t.c))
	return s
}

type Circle struct {
	radius float64
}

func (c Circle) area() float64 {
	return math.Pow(c.radius, 2) * math.Pi
}

func (c Circle) peri() float64 {
	return math.Pi * c.radius * c.radius
}