在過去的幾個月裡,我一直在使用 Go 進行實作。
專為弱程式設計師設計的?
Go 非常容易學習,簡單到我花了一個晚上才完成介紹,之後我已經可以有效率地編寫程式碼了。 我以前學Go的書叫
Google聲稱 Go 的簡單性是它的賣點,而語言是為了最大程度地提高大型團隊的生產力而設計的,但我對此表示懷疑。 有些功能要么缺失,要么過於詳細。 這一切都是因為對開發人員缺乏信任,認為自己無法做正確的事。 這種對簡單性的渴望是語言設計者有意識的決定,為了充分理解為什麼需要它,我們必須了解開發人員的動機以及他們試圖在 Go 中實現的目標。
那麼為什麼它變得如此簡單呢? 這裡有幾句話
這裡的關鍵點是我們的程式設計師(約。:
Google人 )不是研究人員。 一般來說,他們都很年輕,學完才來找我們的,也許他們學的是Java,或C/C++,或是Python。 他們無法理解優秀的語言,但同時我們希望他們能創造出優秀的軟體。 這就是為什麼他們的語言應該易於理解和學習。
他應該很熟悉,大致上和C類似。 在 Google 工作的程式設計師很早就開始了他們的職業生涯,並且大多熟悉製程語言,特別是 C 系列。 新程式語言對快速生產力的要求意味著語言不應該太激進。
什麼? 所以 Rob Pike 基本上是說 Google 的開發人員沒那麼優秀,這就是為什麼他們為白痴創建了一種語言(約。:愚蠢)這樣他們就能夠做某件事。 用什麼傲慢的眼光看待自己的同事? 我一直相信 Google 的開發人員都是從地球上最聰明、最優秀的人中精心挑選出來的。 他們一定能處理更困難的事情嗎?
過於簡單的文物
在任何設計中,簡單都是一個值得追求的目標,但試圖讓事情變得簡單卻很困難。 然而,當嘗試解決(甚至表達)複雜問題時,有時需要複雜的工具。 複雜性和複雜性並不是程式語言的最佳特性,但有一個中間立場,可以創造出易於理解和使用的優雅抽象。
不太善於表達
由於其對簡單性的承諾,Go 缺乏在其他語言中被認為是自然的結構。 乍一看這似乎是個好主意,但實際上它會導致冗長的程式碼。 這樣做的原因應該很明顯——開發人員需要輕鬆閱讀其他人的程式碼,但事實上這些簡化只會損害可讀性。 Go 中沒有縮寫:要嘛很多,要嘛什麼都沒有。
例如,從命令列參數讀取 stdin 或檔案的控制台實用程式如下所示:
package main
import (
"bufio"
"flag"
"fmt"
"log"
"os"
)
func main() {
flag.Parse()
flags := flag.Args()
var text string
var scanner *bufio.Scanner
var err error
if len(flags) > 0 {
file, err := os.Open(flags[0])
if err != nil {
log.Fatal(err)
}
scanner = bufio.NewScanner(file)
} else {
scanner = bufio.NewScanner(os.Stdin)
}
for scanner.Scan() {
text += scanner.Text()
}
err = scanner.Err()
if err != nil {
log.Fatal(err)
}
fmt.Println(text)
}
儘管此程式碼也試圖盡可能通用,但 Go 的強制冗長會妨礙,因此,解決一個簡單的問題會導致大量程式碼。
例如,這裡是相同問題的解決方案
import std.stdio, std.array, std.conv;
void main(string[] args)
{
try
{
auto source = args.length > 1 ? File(args[1], "r") : stdin;
auto text = source.byLine.join.to!(string);
writeln(text);
}
catch (Exception ex)
{
writeln(ex.msg);
}
}
現在誰更具可讀性? 我會把票投給 D。他的代碼更具可讀性,因為他更清楚地描述了操作。 D 使用更複雜的概念(約。:
抄襲地獄
改進 Go 的一個流行建議是通用性。 這至少有助於避免不必要的程式碼複製以支援所有資料類型。 例如,對整數列表求和的函數只能透過為每個整數類型複製貼上其基本函數來實現;沒有其他方法:
package main
import "fmt"
func int64Sum(list []int64) (uint64) {
var result int64 = 0
for x := 0; x < len(list); x++ {
result += list[x]
}
return uint64(result)
}
func int32Sum(list []int32) (uint64) {
var result int32 = 0
for x := 0; x < len(list); x++ {
result += list[x]
}
return uint64(result)
}
func int16Sum(list []int16) (uint64) {
var result int16 = 0
for x := 0; x < len(list); x++ {
result += list[x]
}
return uint64(result)
}
func int8Sum(list []int8) (uint64) {
var result int8 = 0
for x := 0; x < len(list); x++ {
result += list[x]
}
return uint64(result)
}
func main() {
list8 := []int8 {1, 2, 3, 4, 5}
list16 := []int16{1, 2, 3, 4, 5}
list32 := []int32{1, 2, 3, 4, 5}
list64 := []int64{1, 2, 3, 4, 5}
fmt.Println(int8Sum(list8))
fmt.Println(int16Sum(list16))
fmt.Println(int32Sum(list32))
fmt.Println(int64Sum(list64))
}
這個例子甚至不適用於有符號類型。 這種做法完全違背了不重複自己的原則(
D 上的相同範例:
import std.stdio;
import std.algorithm;
void main(string[] args)
{
[1, 2, 3, 4, 5].reduce!((a, b) => a + b).writeln;
}
簡單、優雅、開門見山。 這裡使用的函數是 reduce
對於模板類型和謂詞。 是的,這又比 Go 版本更複雜,但對於聰明的程式設計師來說並不難理解。 哪個範例更易於維護且易於閱讀?
簡單型系統旁路
我想 Go 程式設計師讀到這篇文章一定會口吐白沫,尖叫道:“你做錯了!” 好吧,還有另一種方法可以創建泛型函數和類型,但它完全破壞了類型系統!
看看這個愚蠢的語言修復範例來解決這個問題:
package main
import "fmt"
import "reflect"
func Reduce(in interface{}, memo interface{}, fn func(interface{}, interface{}) interface{}) interface{} {
val := reflect.ValueOf(in)
for i := 0; i < val.Len(); i++ {
memo = fn(val.Index(i).Interface(), memo)
}
return memo
}
func main() {
list := []int{1, 2, 3, 4, 5}
result := Reduce(list, 0, func(val interface{}, memo interface{}) interface{} {
return memo.(int) + val.(int)
})
fmt.Println(result)
}
本次實施 Reduce
是從文章借來的 interface{}
- 一場鬧劇,在語言中只需要繞過打字。 這是一個空接口,所有類型都實現它,為每個人提供完全的自由。 這種程式風格非常醜陋,但這還不是全部。 像這樣的雜技技巧需要使用運行時反射。 正如羅伯派克 (Rob Pike) 在一份報告中提到的那樣,他也不喜歡濫用此功能的人。
這是一個強大的工具,應謹慎使用。 除非絕對必要,否則應避免這樣做。
我會採用 D 模板而不是這些廢話。 怎麼會有人這麼說 interface{}
更具可讀性甚至型別安全?
依賴管理的困境
Go 有一個內建的依賴系統,建構在流行的託管提供者之上
在提出有關此問題的解決方案的問題後,Go 開發團隊創建了
習近平的文化包袱
在我看來,Go 是由那些一生都使用 C 的人和那些不想嘗試新事物的人所開發的。 該語言可以描述為具有額外輪子的 C(原來。:
另一個棘手的問題是 Go 是一種過程語言(就像 C 語言的無聲恐怖一樣)。 您最終會以一種感覺陳舊且過時的過程式風格編寫程式碼。 我知道物件導向程式設計不是靈丹妙藥,但如果能夠將細節抽象化為類型並提供封裝,那就太好了。
為了自己的利益而簡單
Go 的設計很簡單,而且它成功地實現了這一目標。 它是為弱程式設計師編寫的,使用舊語言作為模板。 它配備了簡單的工具來完成簡單的事情。 它易於閱讀且易於使用。
它非常冗長、不起眼,而且對聰明的程式設計師來說很糟糕。
謝謝
來源: www.habr.com