feat: 添加Go语言函数式编程和结构体进阶教程

- 新增Reduce函数实现map-reduce模式
- 实现装饰器模式wrapper函数
- 添加函数闭包和计数器功能
- 完善结构体方法、继承、组合和重写机制
- 增加JSON序列化反序列化及标签处理
- 创建新的学习章节day04关于结构体进阶内容
- 更新README目录结构包含新章节
```
This commit is contained in:
yumaojun03 2026-02-01 16:00:12 +08:00
parent cc0b6694b6
commit 1aa8ec7f3e
10 changed files with 586 additions and 4 deletions

View File

@ -9,4 +9,5 @@
+ [基础语法与环境搭建](./day01/README.md) + [基础语法与环境搭建](./day01/README.md)
+ [复合数据结构](./day02/README.md) + [复合数据结构](./day02/README.md)
+ [函数与结构体](./day03/README.md) + [函数与结构体](./day03/README.md)
+ [结构体(2)与指针](./day04/README.md)

View File

@ -6,6 +6,4 @@
+ [Go语言函数](./function/README.md) + [Go语言函数](./function/README.md)
+ [defer与异常](./error/README.md) + [defer与异常](./error/README.md)
+ [Go语言结构体](./struct/README.md) + [Go语言结构体](./struct/README.md)
+ Go语言指针
+ 扩展反射与内存对齐

View File

@ -48,6 +48,18 @@ func main() {
walkDir(".", func(filePath string) { walkDir(".", func(filePath string) {
fmt.Println(filePath) fmt.Println(filePath)
}) })
//
fmt.Println(Reduce([]int{1, 2, 3, 4}, 0, func(init int, target int) int {
return init + target
}))
wrapper, counter := Wrapper(func() {
logfn("hello")
})
wrapper()
fmt.Println("", counter())
} }
func logfn(log string) { func logfn(log string) {
@ -206,3 +218,34 @@ func walkDir(path string, fn func(string)) {
} }
} }
} }
// Reduce([1 2 3], 0, +) -> 6
// 处理函数 处理聚会方式
func Reduce(nums []int, init int, fn func(init int, target int) int) int {
if len(nums) == 0 {
return init
}
var sum int
for _, num := range nums {
sum += fn(init, num)
}
return sum
}
// 装饰器模式, 函数增强
// @函数作为参数传递
func Wrapper(fn func()) (func(), func() int) {
// 统计函数调用测试
count := 0
return func() {
count++
fmt.Println("开始")
fn()
fmt.Println("结束")
}, func() int {
return count
}
}

View File

@ -0,0 +1,61 @@
<mxfile host="65bd71144e">
<diagram id="14yC9ZJClHcp4uCfI37K" name="第 1 页">
<mxGraphModel dx="834" dy="526" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="2" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="70" y="140" width="100" height="260" as="geometry"/>
</mxCell>
<mxCell id="3" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="370" y="30" width="100" height="460" as="geometry"/>
</mxCell>
<mxCell id="4" value="" style="shape=flexArrow;endArrow=classic;html=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="220" y="270" as="sourcePoint"/>
<mxPoint x="340" y="270" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="5" value="map&lt;div&gt;映射&lt;/div&gt;" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="250" y="220" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="6" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="660" y="130" width="100" height="260" as="geometry"/>
</mxCell>
<mxCell id="7" value="" style="shape=flexArrow;endArrow=classic;html=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="520" y="269.5" as="sourcePoint"/>
<mxPoint x="640" y="269.5" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="8" value="reduce&lt;div&gt;聚合&lt;/div&gt;" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="540" y="220" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="9" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="100" y="640" width="100" height="260" as="geometry"/>
</mxCell>
<mxCell id="10" value="&lt;pre style=&quot;box-sizing: border-box; border-width: 0px; border-style: solid; border-color: currentcolor; caret-color: rgb(1, 5, 10); font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Monaco, Consolas, &amp;quot;Liberation Mono&amp;quot;, &amp;quot;Courier New&amp;quot;, monospace, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;; font-size: 13.6px; --fonts-regular: -apple-system, &amp;quot;Segoe UI&amp;quot;, system-ui, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;; margin-top: 0px; padding: 16px; line-height: 1.45; border-radius: 4px; overflow-wrap: normal; position: relative; overflow: auto; color: rgb(24, 28, 33); text-align: start; margin-bottom: 0px !important; background-color: rgba(0, 48, 96, 0.063);&quot; class=&quot;code-block&quot;&gt;&lt;span style=&quot;text-wrap-mode: wrap; background-color: rgba(255, 255, 255, 0.1);&quot;&gt;defer 1&lt;/span&gt;&lt;/pre&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="100" y="840" width="100" height="60" as="geometry"/>
</mxCell>
<mxCell id="11" value="defer 2" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="100" y="780" width="100" height="60" as="geometry"/>
</mxCell>
<mxCell id="12" value="defer 3" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="100" y="720" width="100" height="60" as="geometry"/>
</mxCell>
<mxCell id="14" value="" style="shape=flexArrow;endArrow=classic;html=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="240" y="770" as="sourcePoint"/>
<mxPoint x="240" y="680" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="15" value="" style="shape=flexArrow;endArrow=classic;html=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="50" y="690" as="sourcePoint"/>
<mxPoint x="50" y="790" as="targetPoint"/>
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

5
day04/README.md Normal file
View File

@ -0,0 +1,5 @@
# 结构体(2)与指针
+ [Go语言结构体](./struct/README.md)
+ Go语言指针
+ 扩展反射与内存对齐

31
day04/struct/01.drawio Normal file
View File

@ -0,0 +1,31 @@
<mxfile host="65bd71144e">
<diagram id="-BhJ9crSOhd-5Krr8EOO" name="第 1 页">
<mxGraphModel dx="1134" dy="526" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="2" value="交通工具" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="294" y="130" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="6" value="行驶( Drive)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="450" y="145" width="190" height="30" as="geometry"/>
</mxCell>
<mxCell id="7" value="" style="shape=flexArrow;endArrow=classic;html=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="70" y="159.5" as="sourcePoint"/>
<mxPoint x="210" y="159.5" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="8" value="自行车" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="120" y="250" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="9" value="摩托车" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="300" y="250" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="10" value="汽车" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="480" y="250" width="120" height="60" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

155
day04/struct/README.md Normal file
View File

@ -0,0 +1,155 @@
# 结构体(2)
## 方法
```go
// func ChangePersonAge(p *Person, newAge int)
func (p *Person) ChangePersonAge(newAge int) {
p.age = newAge
}
// ChangePersonAge(&p1, 22)
// p1.ChangePersonAge(22)
```
## 继承
Bike 继承了TranficTool 所有属性和方法
```go
type TranficTool struct {
Name string
Speed int
Color string
}
// Drive 是交通工具的行驶方法
func (t *TranficTool) Drive() {
fmt.Printf("%s 正在以 %d 的速度前进\n", t.Name, t.Speed)
}
// Bike 是自行车
type Bike struct {
// 嵌入了交通工具, 继承了交通工具的属性和方法 (可以上班)
TranficTool
}
```
## 组合
Bike 继承了TranficTool 所有属性和方法, 同时还组合了PlayTool 的所有的属性的方法(组合的时候避免有相同的字段)
```go
type TranficTool struct {
Name string
Speed int
Color string
}
// Drive 是交通工具的行驶方法
func (t *TranficTool) Drive() {
fmt.Printf("%s 正在以 %d 的速度前进\n", t.Name, t.Speed)
}
// PlayTool 是一个表演工具
type PlayTool struct{}
func (p *PlayTool) Play() {
fmt.Println("开始我的表演: 后空翻")
}
func (b *PlayTool) Jump() {
fmt.Println("海豚跳: 高级版")
}
// Bike 是自行车
type Bike struct {
// 嵌入了交通工具, 继承了交通工具的属性和方法 (可以上班)
TranficTool
// 嵌套了PlayTool, 继承了PlayTool的方法(可以表演)
PlayTool
}
```
## 重写
我们继承来的方法 不满足我们的需求,那么我们就需要重写方法
```go
// review的核心逻辑: 优先找方法接收者所属的结构体的方法(优先级最高)
// 如果找不到,再去找嵌入的结构体的方法
// 如果嵌入的结构体也找不到,再去找嵌入的结构体的嵌入结构体的方法
// 直到找到为止
// 等同于重写(Rewrite),覆盖了之前的继承而来的方法
func (b *Bike) Jump() {
fmt.Println("海豚跳 基础版")
}
```
重写为程序提供了更高的灵活性(兼容性)
## Json
### 序列化与反序列化
一种常见的序列化的方法,也是 常用于数据传递,也实现服务的复制, 既然数据都复制了也就实现的深拷贝(现在, 不是一个对象的完整服务)
常见的JSON库: json, go-json, 还有些第三方库: https://github.com/json-iterator/go
当前 Go 标准库的 json 库已经足够我们使用, 并且兼容性高,性能也强,最新的版本里面
![alt text](image.png)
+ 序列化把结构体序列化为JSON字符串 (obj -> json(bytes)), json.Marshal()
```go
// 类型转换: []byte -> string (需要字符辩解库: acsic, unicode, gbk, gb18030, gb2312, gbk-sjis-x0213, gb18030-sjis-x0213, gb2312-sjis-x0213, gbk-sjis-x0212, gb18030-sjis-x0212, gb2312-sjis-x0212, gbk-sj)
// [123 34 78 97 109 101 34 58 34 232 135 170 232 161 140 232 189 166 34 44 34 83 112 101 101 100 34 58 50 48 44 34 67 111 108 111 114 34 58 34 233 187 145 232 137 178 34 125]
fmt.Println(bikeJson)
// 编码点 对应的 字符串
// // 123 34 78 97 109 101 34 58 34 33258 34892 36710 34 44 34 83 112 101 101 100 34 58 50 48 44 34 67 111 108 111 114 34 58 34 40657 33394 34 125 (uicode 码表)
// {"Name":"自行车","Speed":20,"Color":"黑色"}
fmt.Println("bike json string: ", string(bikeJson))
```
+ 反序列化: 把JSON字符串 反序列化为结构体 (json(bytes) -> obj), json.Unmarshal()
```go
// json.Unmarshal()
bike_cloned := &Bike{}
if err := json.Unmarshal(bikeJson, bike_cloned); err != nil {
panic(err)
}
fmt.Println("bike source:", bike)
fmt.Println("bike clone:", bike_cloned)
```
注意基于 Json来复制对象是有属性无法复制的比如指针指针类型无法复制指针类型需要特殊处理
## Json标签
json标签: 用来告诉json库如何将结构体字段序列化为JSON字符串
```json
// Name => name
// Speed => speed
// Color => color
{"Name":"自行车","Speed":20,"Color":"黑色"}
```
Json Tag: Struct Tag 核心能力通过给结构体字段添加标签来告诉json库如何将结构体字段序列化为JSON字符串(key 映射关系)
```go
// JSON: {"name":"自行车","speed":20,"color":"黑色"}
type TranficTool struct {
// `` 表示字符串 都是 Struct Tag, 结构体标签lib 反射使用
Name string `json:"name"`
Speed int `json:"speed"`
Color string `json:"color"`
move bool
}
```

BIN
day04/struct/image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

76
day04/struct/json.drawio Normal file
View File

@ -0,0 +1,76 @@
<mxfile host="65bd71144e">
<diagram id="5nK-vBOAah09B86iugSh" name="第 1 页">
<mxGraphModel dx="1134" dy="607" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="3" value="obj" style="ellipse;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="80" y="230" width="120" height="80" as="geometry"/>
</mxCell>
<mxCell id="4" value="" style="shape=flexArrow;endArrow=classic;html=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="254" y="269.5" as="sourcePoint"/>
<mxPoint x="514" y="269.5" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="5" value="编码规则:&lt;div&gt;json&lt;/div&gt;" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="354" y="210" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="7" value="bytes数组:&lt;div&gt;010101010&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="580" y="240" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="8" value="" style="ellipse;shape=cloud;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="580" y="370" width="120" height="80" as="geometry"/>
</mxCell>
<mxCell id="9" value="bytes数组:&lt;div&gt;010101010&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="580" y="510" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="10" value="网线0101" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="720" y="395" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="11" value="" style="shape=flexArrow;endArrow=classic;html=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="550" y="540" as="sourcePoint"/>
<mxPoint x="220" y="540" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="12" value="obj" style="ellipse;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="80" y="490" width="120" height="80" as="geometry"/>
</mxCell>
<mxCell id="13" value="编码规则:&lt;div&gt;json&lt;/div&gt;" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="360" y="490" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="14" value="序列化" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="354" y="280" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="15" value="反序列" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="360" y="555" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="16" value="Actor" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" vertex="1" parent="1">
<mxGeometry x="340" y="70" width="30" height="60" as="geometry"/>
</mxCell>
<mxCell id="17" value="字符串" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="580" y="80" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="18" value="" style="shape=flexArrow;endArrow=classic;html=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="640" y="220" as="sourcePoint"/>
<mxPoint x="640" y="160" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="19" value="字符解码" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="680" y="180" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="20" value="unicode&lt;div&gt;&lt;div&gt;utf-8&amp;nbsp;&lt;/div&gt;&lt;/div&gt;" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="560" y="180" width="60" height="40" as="geometry"/>
</mxCell>
<mxCell id="21" value="" style="shape=flexArrow;endArrow=classic;html=1;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="430" y="120" as="sourcePoint"/>
<mxPoint x="560" y="120" as="targetPoint"/>
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

212
day04/struct/main.go Normal file
View File

@ -0,0 +1,212 @@
package main
import (
"encoding/json"
"fmt"
)
func main() {
person := &Person{
Name: "张三",
age: 18,
}
// 通过一个一个的函数 去处理数据的 编程方式,就是面向过程编程
ChangePersonAge(person, 28)
// 修改体重 ChangeWeight 的函数
fmt.Println(person.age)
// 面向对象编程,有更好封装,也贴近与现实世界
person.ChangePersonAge(20)
fmt.Println("修改后的年龄:", person.age)
fmt.Println(person.age)
person.我的名字()
// 修改了wei lght吗
person.SetWeight(80)
fmt.Println("修改后的体重:", person.Weight)
fmt.Println("结构体与面向对象")
// 创建交通工具
// 能做的动作 -> 海豚跳(Jump)
bike := &Bike{TranficTool{
Name: "自行车",
Speed: 20,
Color: "黑色",
}, PlayTool{}}
// bike.TranficTool.Drive()
bike.Drive()
// bike.PlayTool.Play()
bike.Play()
// bike.PlayTool.Jump()
// bike.Jump()
// Rewrite 方法重写
bike.Jump()
bike.PlayTool.Jump()
// 炸街
motor := &Moto{TranficTool{
Name: "摩托车",
Speed: 80,
Color: "蓝色",
}}
motor.Drive()
motor.Music()
// 打开空调
car := &Car{TranficTool{
Name: "汽车",
Speed: 120,
Color: "白色",
}}
car.Drive()
car.AirConditioning()
// Json
bike.move = true
bikeJson, err := json.Marshal(bike)
if err != nil {
panic(err)
}
// 类型转换: []byte -> string
fmt.Println(bikeJson)
fmt.Println("bike json string: ", string(bikeJson))
// 123 34 78 97 109 101 34 58 34 33258 34892 36710 34 44 34 83 112 101 101 100 34 58 50 48 44 34 67 111 108 111 114 34 58 34 40657 33394 34 125
for _, b := range string(bikeJson) {
fmt.Printf("%v ", b)
}
// json.Unmarshal()
bike_cloned := &Bike{}
if err := json.Unmarshal(bikeJson, bike_cloned); err != nil {
panic(err)
}
fmt.Println("bike source:", bike)
fmt.Println("bike clone:", bike_cloned)
}
// Person 是一个表示人的结构体,包含姓名、年龄、性别、体重和喜欢的颜色等字段。
// 也是一个复合数据类型。
type Person struct {
Name string
// 不对外暴露的字段
age int
Gender Gender
Weight uint
FavoriteColor []string
}
// func ChangePersonAge(p *Person, newAge int)
func (p *Person) ChangePersonAge(newAge int) {
p.age = newAge
}
// 修改的
// SetWeight(p *Person)
func (p *Person) SetWeight(newWeight uint) {
p.Weight = newWeight
}
// 不涉及到对象修改的,把这个方法绑定给值也是可以
// GetWeight(p Person)
func (p Person) GetWeight() uint {
return p.Weight
}
func (p *Person) 我的名字() string {
return p.Name
}
// GenderXXX 表示枚举值
// Gender 是一种自定义类型,底层类型是 int
// Gender != int
type Gender int
// Sex == Gender
type Sex = Gender
const (
GenderMale Gender = iota
GenderFemale
)
// ChangePersonAge 修改Person的年龄
func ChangePersonAge(p *Person, newAge int) {
// 自动解开引用(*p)
// * -> 解引用(Unbox)
// (*p).age = newAge
// p 指针类型, 自动解引用
// . 访问字段
// 自动解引用
// p.age == (*p).age
// 所以可以直接写成下面这样
p.age = newAge
}
type TranficTool struct {
// `` 表示字符串 都是 Struct Tag, 结构体标签lib 反射使用
Name string `json:"name"`
Speed int `json:"speed"`
Color string `json:"color"`
move bool
}
// Drive 是交通工具的行驶方法
func (t *TranficTool) Drive() {
fmt.Printf("%s 正在以 %d 的速度前进\n", t.Name, t.Speed)
}
// PlayTool 是一个表演工具
type PlayTool struct{}
func (p *PlayTool) Play() {
fmt.Println("开始我的表演: 后空翻")
}
func (b *PlayTool) Jump() {
fmt.Println("海豚跳: 高级版")
}
// Bike 是自行车
type Bike struct {
// 嵌入了交通工具, 继承了交通工具的属性和方法 (可以上班)
TranficTool
// 嵌套了PlayTool, 继承了PlayTool的方法(可以表演)
PlayTool
}
// review的核心逻辑: 优先找方法接收者所属的结构体的方法(优先级最高)
// 如果找不到,再去找嵌入的结构体的方法
// 如果嵌入的结构体也找不到,再去找嵌入的结构体的嵌入结构体的方法
// 直到找到为止
// 等同于重写(Rewrite),覆盖了之前的继承而来的方法
func (b *Bike) Jump() {
fmt.Println("海豚跳 基础版")
}
// Bike 重写了 Drive 方法,定制了自己的 Drive 方法
func (b *Bike) Drive() {
fmt.Printf("%s 正在以 %d 的速度 脚踏前进\n", b.Name, b.Speed)
}
// Moto 是摩托车
type Moto struct {
// 嵌入了交通工具, 继承了交通工具的属性和方法
TranficTool
}
func (m *Moto) Music() {
fmt.Println("炸街")
}
// Car 是汽车
type Car struct {
// 嵌入了交通工具, 继承了交通工具的属性和方法
TranficTool
}
// AirConditioning 是汽车的空调方法
func (c *Car) AirConditioning() {
fmt.Println("打开空调")
}