通过学习Golang而意识到的事情
非常感谢您阅读2020年Classi降临日历的第16天文章!
我是一名服务器端工程师@willsmile。最近,我开始对住房和汽车产生了兴趣,并且在考虑具体事例时,我意识到它们会“自然地”出现,这给我带来了一种“不自然”的感觉。
序言
考虑到本文标题,你可能会对“为什么要学习Golang”这个问题产生疑问,所以我将在下面的主题中详细解释我的学习目标。在此之前,我想提及一下我作为一个有1年9个月工作经验的人对今年的职业发展目标。
总之,今年我的目标是成为一个“复眼”人。这个词来源于加谷先生的知识复眼思考法(一本非常有趣的书,我强烈推荐),我想表达的是为了与拥有不同立场和专业的人顺畅地合作,要能够理解对方的观点和重要性,以及为什么要理解,并且能够采取行动来实现理解。
这个问题
为什么选择学习Go语言作为学习目标?
从上述目标出发,我希望学习一种与我在工作中主要使用的Ruby编程语言不同的风格的编程语言,并进行比较,以了解它们之间是否存在差异。
因此,我列出了以下作为可能的语言选择,但考虑到我经常使用的工具中有许多是基于Go的(例如,yay,direnv,Hugo),出于学习资源的丰富性考虑,我决定进一步学习Golang。
1. Golang(Go语言)
2. Elm语言
3. Haskell语言
怎样学习呢?
国家说来,我按照下面的四个阶段来设计自己的学习计划。(我现在处于第三个阶段)
-
- 段階1:何かを作れるように,最低限必要な知識を公式ドキュメントから獲得すること
実際作ったものはこちらのツール(s2test: A Simple Smoke Test Tool)です.いまの自分からみると,とてもRubyらしくGolangを使ってしまった感があります.
段階2:Golangに関する面白い記事・講演ビデオを広く読む・見て,言語を作った・使っている人がどう思っているのか(言語の特徴)を知ること
スキマ時間の活用と学びの“冗長性”向上の観点から,この段階2をダラダラやるのは個人的にとても好きですが,効率を求める場合,この段階を一旦飛ばしてもいいと思います.
段階3:Golangに関する良い本を選んで,その中のGolang特徴である部分の内容を精読すること
実際読んでいる本は,こちら(The Go Programming Language)です.
段階4:上記の過程から学んだことを踏まえて,段階1で作ったものを作り直すこと
通过之前的学习,你意识到了什么?
总结起来,“有时候不能使用继承”的意思。以下详细解释了认识到这一点的过程。
在Golang中的”继承”
众所周知,Golang中并没有继承的概念(尤其是在面向对象编程的语境下)。取而代之的是嵌入结构体(Embedding)和接口(Interface),它们与继承类似(但并不完全相同,请勿混淆)。
结构体的嵌入
这是指在字面上,在结构体中嵌入结构体这一意思。
正如以下代码示例所示,通过在汽车(Motorcar)和自行车(Bicycle)中嵌入人工物(Artifact),可以使由人工物定义的制造商(Manufacturer)字段在汽车和自行车中可用。此外,处理人工物的方法也可以处理汽车和自行车。这样就构建了“准is-a关系”。
然而,需要注意的是,人工物虽然是独立的实体,但它存在于汽车(或自行车)内,并不能称为亲子关系。这一点可以从以下源代码中变量mc的声明和赋值方式(Artifact不能省略)中看出来。
package main
import "fmt"
type Artifact struct {
Manufacturer string
}
type Motorcar struct {
Artifact
HorsePower int
}
type Bicycle struct {
Artifact
NormalSpeed int
}
func (a Artifact) Info() {
fmt.Printf("Made by %s\n", a.Manufacturer)
}
func main() {
mc := Motorcar{
Artifact: Artifact{
Manufacturer: "Toyota",
},
HorsePower: 100,
}
bc := Bicycle{}
bc.Manufacturer = "Bianchi"
bc.NormalSpeed = 20
mc.Info()
bc.Info()
}
界面 .
我发现要简洁地解释”接口是什么?”是很困难的,所以借用@tenntenn的话来解释。在Go语言中,”抽象化的概念只存在于接口”。在编程中,抽象化的目的是降低模块的耦合度,也就是关注点的分离。
根据以下代码的具体示例,我们将关注汽车(Motorcar)和自行车(Bicycle)的运输行为,并将其定义为交通工具(Vehicle)的接口。通过这样做,我们可以将汽车和自行车都视为能够运输的交通工具,暂时忽略它们各自具有的字段(马力,常速)和通过方法定义的运输处理方式(详细信息请参阅注释)。
package main
import "fmt"
type Motorcar struct {
HorsePower int
}
type Bicycle struct {
NormalSpeed int
}
type Vehicle interface {
Transport()
}
func (m Motorcar) Transport() {
// エンジンの性能による速度が決まる
fmt.Printf("Moving by a motor which provides power of %d kW.\n", m.HorsePower)
}
func (b Bicycle) Transport() {
// 車体の構造上の性質による速度が決まる
fmt.Printf("Moving by a human and generally run at speed of %d km/h.\n", b.NormalSpeed)
}
func main() {
var mc, bc Vehicle
mc = Motorcar{
HorsePower: 100,
}
bc = Bicycle{
NormalSpeed: 20,
}
mc.Transport()
bc.Transport()
}
究竟为什么呢?
在学习Golang结构体的嵌入和接口时,我脑海中浮现出了“为什么继承不可行?”和“为什么在设计语言时故意排除了继承?”这两个问题。经过一番调查研究,我意识到,“在某些情况下,使用继承会带来很大的缺点。”
由于详细解释答案会使得篇幅过长,故在此不再详细阐述。如果您想要详细了解,请推荐您阅读参考文献2(书籍,第6章:通过继承获取行为、第7章:通过模块共享角色行为)和3(文章)。
作者的评论
从这次经历中我学到的是,不管是编程语言还是人,在设计上都存在着不同的观点,也会持有不同的观点。与其将不同之处分为“喜欢”和“讨厌”,不如意识到这种差异,并思考其中的原因,这样可以获得有益的启示。
文献引用
- 《エキスパートGo》是一本使用Ruby作为敏捷开发教程的实用面向对象设计的书籍,第二版。《君の継承の使い方は間違っている》询问Go是否是面向对象的语言。