26、接口
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
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构