使用 Golang 的新泛型,我們有波浪號運算子 ~ 它將匹配底層型別。在什么情況下不匹配底層型別是有效的?我試圖理解為什么波浪線的當前行為不是默認行為。似乎沒有必要同時支持兩者。
例如,你為什么要寫
interface { int }
并不是
interface { ~int }
撰寫一個嚴格到無法接受類似的方法對您有什么好處
type MyInt int
為什么波浪號行為不是默認行為,因此該語言不需要其他運算子?
uj5u.com熱心網友回復:
不使用~運算子意味著您只接受列出的確切型別。為什么這很重要?
您可能希望使用確切型別的值來設定其他變數,否則需要進行型別轉換。因為俗話說“新型別,新方法集”。具有相同基礎型別的新型別有自己的方法集。
您可能想要該值的“原始”行為,如果它有不同的方法集,它可能會改變。
例如,假設您要列印這樣的數字:
type Num interface{ ~int }
func foo[T Num](v T) {
fmt.Println(v)
}
如果MyInt有一個String() string方法:
type MyInt int
func (m MyInt) String() string { return "bar" }
輸出可能不是foo()想要的,因為fmt包檢查列印的值是否有String() string方法,如果有,則呼叫它來獲取其string表示:
foo(1)
foo(MyInt(1))
這將輸出(在Go Playground上嘗試):
1
bar
如果您只允許int:
type Num interface{ int }
您仍然可以使用型別轉換foo()來呼叫type 的值:MyInt
foo(1)
x := MyInt(1)
foo(int(x))
輸出將是foo()想要的,而不是MyInt想要的(在Go Playground上試試這個):
1
1
是的,如果它自己會進行轉換,這也是可能foo()的,但這清楚地表明你想要一個純粹的int, withint的行為,而不是int具有不同的自定義行為的東西。
uj5u.com熱心網友回復:
為什么波浪號行為不是默認值
因為撰寫這樣一個func Foo[T int](v T)接受非int. 那么intin interface 約束的含義將與其他任何地方都不相同。(更多關于這個討論)
撰寫一個如此嚴格的方法對您有什么好處 [...]
事實上,如果約束只包含一種確切的型別,那么使用型別引數是沒有意義的。如果約束的型別集具有基數 1,則應洗掉型別引數。
像這樣的功能:
func Foo[T int](v T)
只能用 exact 實體化int,所以它可以(而且應該!)簡單地用常規引數撰寫:
func Foo(v int)
當型別集基數為 N 時,它包括單個波浪號型別,但也包括聯合,基本上不可能撰寫詳盡的型別切換,因為不允許使用~in陳述句(但是?):case
func Foo[T ~int | ~string](v T) {
switch t := any(v).(type) {
case int: // ok
case string: // ok
// how to match other possible types then?
}
}
在這種特殊情況下,僅當約束包含精確型別時才能撰寫窮舉型別開關:
func Foo[T int | string](v T) {
switch t := any(v).(type) {
case int: // ok
case string: // ok
default:
panic("should not occur")
}
}
這在實踐中不應該經常出現:如果你發現自己打開了型別引數,你應該問自己這個函式是否真的需要泛型。但是,在設計代碼時,用例是相關的。
uj5u.com熱心網友回復:
為什么波浪號行為不是默認行為,因此該語言不需要其他運算子?
因為如果近似值是無條件的默認值,則您無法表達您的多型函式需要 aint而不是 a的事實MyInt。然后你必須引入一個像 strict 和 write 這樣的運算子%int。一無所獲。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/473038.html
