PHP vs Go,為什麼 Go 不支援命名引數呼叫函式?
大家好,我是煎魚。
之前在《Go 語言設計哲學[1]》電子書中分享了《為什麼 Go 不支援函式過載和預設引數?》的思考和原因。最近有一位從其他程式語言轉型 Go 的同學提出瞭如下靈魂拷問。
“為什麼 Go 不能像 PHP、Python 一樣,在呼叫函式時,直接帶上引數名和值一起傳入。這樣就不用特意去看這個函式的形參的命名、型別等。明明 PHP8 都支援了?”
今天針對命名引數這個特性展開思考,看看 Go 怎麼回事。
命名引數
如果有了命名引數這個功能特性,在我們呼叫函式/方法時,傳入函式的引數不需要固定位置,位置可以隨意調整,名字對就行。甚至有的工具會基於此,做自動化的檔案等自描述的場景。
PHP8 的例子:
function hello(string $name, int $age) {
echo $name, $age;
}
// 兩次呼叫的引數位置不一樣
hello(name:'煎魚', age:18);
hello(age:18, name:'煎魚');
理想中 Go 的例子:
package main
func sum(a int, b int) int {
return a + b
}
func main() {
resp := sum(a=7, b=28)
println(resp)
}
由於不支援,執行編譯就會報錯:
./prog.go:8:15: syntax error: unexpected = in argument list; possibly missing comma or )
Go 必須是如下程式碼:
func sum(a int, b int) int {
return a + b
}
func main() {
resp := sum(7, 28)
println(resp) // 輸出結果:35
}
也就是按函式所宣告的引數位置傳入,才能執行成功。
設計哲學
Go 語言在錯誤處理、函式過載以及預設引數等社群議題討論時,總會祭出其的設計理念是:“顯式大於隱喻”,追求明確,顯式,要不就是 “less is more”。
每次看到只要不滿足這個理念的提案、討論,基本 Go 團隊可以圍繞這個論據給出一堆理由後拒絕掉。
本文提到的帶命名引數傳入函式,看起來非常顯式,很明確了。似乎很符合 Go 的設計哲學理念,感覺不應該沒有才對?
社群思考
在 golang-nuts 郵件群組的多年討論中,涉及到以下幾類論據作為支撐:
這是一個語言設計和可讀性問題,“命名引數” 和 “預設引數” 基本是成配套出現在語言設計中,需要一併考量合適與否。會出現一加就相當於要引入許多新語法特性了,能玩出騷操作。 引入這類特性會給 Go 帶來新語法複雜度,如果函式引數名修改了,那是不是破壞相容性?是不是呼叫方全都得改一遍?如果出現同名的引數名,誰先誰後?怎麼覆蓋?過長的話,函式呼叫會不會過於難接受?組合結構體覆蓋方法時,方法引數名需不需要保持一致?會產生一大堆新問題。 引入後會產生大量的函式可選引數(命名引數+預設引數),原本只需要知道函式形參是什麼,結果引入後需要檢視名字、預設值以及對應的預設邏輯等,會加大程式設計師心智負擔。 編譯器本身不需要關注這些資訊,為這個特性加大編譯器的各項開銷是不必要的,沒有理由讓編譯器在編譯程式碼中儲存函式的引數名稱(需要具體考究深意)。
我們在討論中也有提到,這個特性可以藉助 go:generate
的特性來實現類似的功能,有興趣的朋友可以看看 go-named-params[2] 這個開源庫。
顯然官方態度是,增加命名引數特性的弊大於利,貿然增加會影響到 Go 本身標榜的優勢(簡潔)。認為大可不必加,工具的問題需要讓工具自己解決。
總結
在這篇文章中,我們針對其他程式語言既有的 “命名引數” 特性進行了分析和說明。顯然 Go 團隊在討論中,認為該項特性對於靜態語言,尤其對於 Go 團隊來講,似乎好處太少,加了會影響自己的風格(less is more),還可能會影響效能,真是大可不必。
各語言間的功能特性對比,是個老大難的問題。如果都一樣,那豈不是搞個大單體程式語言算了?這顯然是不現實的。
參考資料
Go 語言設計哲學:
[2]go-named-params:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024922/viewspace-2936167/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- PHP 都有,Go 憑什麼不支援命名引數呼叫函式?PHPGo函式
- 為什麼 Go 裡值為 nil 可以呼叫函式?Go函式
- 為什麼不建議函式有太多引數?函式
- GO語言————6.7 將函式作為引數Go函式
- Go函式接收可變引數Go函式
- 揭秘 Go 中的函式引數Go函式
- Go語言Slice作為函式引數詳解Go函式
- 我為什麼從php轉go?PHPGo
- PHP->GO 基礎-函式PHPGo函式
- Go實現PHP常用函式GoPHP函式
- Go 為什麼不支援可重入鎖?Go
- 為什麼 Go 不支援 []T 轉換為 []interfaceGo
- GO語言————6.2 函式引數與返回值Go函式
- 為什麼 Go1.22 for 迴圈要支援整數範圍?Go
- PHP FFI呼叫go,居然比go還快PHPGo
- 函式的呼叫方式和引數函式
- Python中函式為什麼可以當做引數使用?Python函式
- 兄弟連go教程(15)函式 - 延遲呼叫Go函式
- Go 為什麼不支援字首自增運算子?Go
- go 呼叫 shell 指令碼 如何傳遞引數Go指令碼
- Rust vs. Go:為什麼強強聯合會更好RustGo
- 清華尹成帶你實戰GO案例(34)Go 函式命名返回值Go函式
- Go 讀者提問:Go 函式返回值命名有存在的意義嗎?Go函式
- python不定長引數如何呼叫函式?Python函式
- Go init 函式Go函式
- Go 匿名函式Go函式
- Python中將函式作為另一個函式的引數傳入並呼叫Python函式
- 像跟蹤分散式服務呼叫那樣跟蹤 Go 函式呼叫鏈分散式Go函式
- Go 為什麼不在語言層面支援 map 併發?Go
- Go for PHP Developers: Structs vs Classes (翻譯)GoPHPDeveloperStruct
- 陣列作為函式引數陣列函式
- Python函式引數和註解是什麼Python函式
- Go 入門 – 包,函式和變數Go函式變數
- Go 之基礎速學 (五) golang 裡函式以及函式之間引數的傳遞Golang函式
- 函式呼叫引數變數傳值的問題函式變數
- PHP 函式可變數量的引數列表PHP函式變數
- go 閉包函式Go函式
- Go 語言函式Go函式