前幾日跟朋友探討他新寫的程式語言的特性設計時,討論到他希望 interface 與 record 都是 structural 時,發現了一些小小的設計限制,所以在這裡紀錄下來。
Go 的兩個特性 [local-0]
Go 的兩個特性 [local-0]
- struct 是 nominal:兩個欄位相同的 struct 依然是不同型別
- interface 是 structural:只看 method set 自動匹配,不需顯式宣告
兩者看起來是各自獨立的設計選擇,然而
如果 struct 是 structural [local-1]
如果 struct 是 structural [local-1]
interface Hello { hello() }
type T = struct {}
func (t *T) hello() { ... }
- structural rule 下
T只是形狀{}的一個參考用標籤,並不會被型別系統認知到 - structural subtyping 下,所有 record 在結構上都包含空欄位集,所以全部都得到了
hello()的實現 - 結合 structural interface 認為有方法就算實作,就等於所有 record 類型都實現了
Hello - 若其他類型也各自定義
hello(),要使用哪個就由 method resolution 演算法決定,這個結果通常是非常不穩定的(更不用說這裡還需要底下實現紀錄是哪個 record 實現了 method,與類型系統設計不匹配,讓 resolution 的結果更難被理解與信任)
所以 Go 選擇 nominal struct 是出於真正的約束所限,一但選擇 structural interface 就需要對其他部分做出讓步。