golang中接口详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package main
 
import (
    "fmt"
)
 
type Sayer interface {
    say()
}
type Mover interface {
    move()
}
type Animal interface {
    // 接口与接口嵌套创造出新的接口,Animal接口有Sayer和Mover两个接口中的所有方法
    Sayer
    Mover
}
type Cat struct {}
func (c Cat) say() {
    fmt.Println("喵喵喵")
}
func (c Cat) move() {
    fmt.Println("猫走路呢")
}
type Dog struct {}
func (d *Dog) say() {
    fmt.Println("汪汪汪")
}
 
func main() {
    // 1. 实现接口的条件?
        // 一个对象只要实现了接口中的所有方法,就实现了该接口
 
    // 2. 接口命名规范:接口名称建议以er结尾
 
    // 3. 实现了该接口有什么作用?
        // 接口类型变量可以存储所有实现了该接口的实例
    var s Sayer
    s = Cat{}  // s接口类型变量存储Cat{}实例
    s.say()
    s = &Dog{}  // s接口类型变量存储Dog{}实例
    s.say()
 
    // 4. 值接受者和指针接受者实现接口的区别?
    // 4.1 值接受者
    c := Cat{}
    s = c
    s.say()
    s = &c
    s.say()
    // 结论:使用值接受者实现该接口后,不论是Cat{}结构体还&Cat{}结构体指针变量都可以赋值给该接口变量
    // 因为Go语言中有对指针类型变量求值的语法糖,dog指针fugui内部会自动求值*fugui
 
    // 4.2 指针接受者实现该接口
    //s = Dog{}  报错
    s = &Dog{}
    s.say()
    // 结论:s接口变量只能接收&Dog{}结构体指针类型,不能接收Dog{}结构体类型
 
    // 5. 一个类型可以实现多个接口,而接口间彼此独立,不知道对方的实现
    var m Mover
    m = Cat{}
    s = Cat{}
    s.say()
    m.move()
 
    // 6. 接口嵌套:接口与接口间可以通过嵌套创造出新的接口
    var a Animal
    a = Cat{}
    fmt.Println("====6===")
    a.say()
    a.move()
 
    // 7. 空接口: 指没有定义任何方法的接口,因此任何类型都实现了空接口,空接口类型的变量可以存储任意类型的变量
    // 8. 空接口的应用
        // 8.1 空接口作为函数的参数,可以接收任意类型的数据
        // 8.2 使用空接口可以实现保存任意值的字典
        // 8.3 类型断言:空接口可以存储任意类型的值,那我们如何获取存储的具体数据呢
        // 一个接口的值(简称接口值)是由一个具体类型和一个具体类型的值两部分组成,
        // 这两部分分别称为接口的动态类型和动态值
        // 8.4 类型断言语法:i.(T)
        // 该语法返回两个参数,第一个参数是x转化为T类型后的变量,第二个值是一个布尔值,若为true则表示断言成功,为false则表示断言失败。
 
    var i interface{}
    i = true
    // 单个类型断言
    if v, ok := i.(int); ok {
        fmt.Println(v)
    } else {
        fmt.Println("i不是int类型")
    }
 
    // 多个类型断言
    switch v := i.(type) {
    case string:
        fmt.Println(v, "字符串类型")
    case int:
        fmt.Println(v, "int类型")
    default:
        fmt.Println("未知类型")
    }
 
    /*
    因为空接口可以存储任意类型值的特点,所以空接口在Go语言中的使用十分广泛。
    关于接口需要注意的是,只有当有两个或两个以上的具体类型必须以相同的方式进行处理时才需要定义接口。
    不要为了接口而写接口,那样只会增加不必要的抽象,导致不必要的运行时损耗。
    */
 
}

  

参考链接:https://www.topgoer.com/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/%E6%8E%A5%E5%8F%A3.html

posted @   专职  阅读(337)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示