2 回答

TA貢獻1836條經(jīng)驗 獲得超3個贊
是和不是。
您幾乎可以使用鏈式 API 到達那里。這適用于許多標準 LINQ 方法,例如Skip
、Take
、Where
、First
等Last
。
不起作用的是,當您需要切換到流/流中的另一種通用類型時。
Go 泛型不允許方法具有除定義它們的接口/結構之外的其他類型參數(shù)。例如,你不能有一個結構Foo[T any]
,然后有一個方法Bar[O any]
這是方法所必需的,比如Select
你有一種類型的輸入和另一種類型的輸出。
但是,如果您不使用鏈接而只是使用普通函數(shù)。那么您可以獲得非常接近的功能。
我已經(jīng)在這里完成了:https ://github.com/asynkron/gofun
這是一個通過模擬協(xié)程實現(xiàn)的完全懶惰的可枚舉實現(xiàn)。
在這里不起作用的是Zip
需要同時枚舉兩個可枚舉的函數(shù)。(雖然有辦法破解它。但沒什么好看的)

TA貢獻1806條經(jīng)驗 獲得超5個贊
Go 的參數(shù)多態(tài)性與 C# 或 Java 中的泛型實現(xiàn)之間的一個顯著區(qū)別是 Go(仍然)沒有針對類型參數(shù)的協(xié)方差/反方差的語法。
例如,在 C# 中,您可以擁有實現(xiàn)IComparer<T>
和傳遞派生容器類的代碼;或者在 Java 中典型Predicate<? super T>
的流 API。在 Go 中,類型必須完全匹配,并且使用不同的類型參數(shù)實例化泛型類型會產生不同的命名類型,這些類型不能相互分配。另請參閱:為什么 Go 不允許將一個泛型分配給另一個泛型?
Go 也不是 OO,所以沒有繼承的概念。您可能有實現(xiàn)接口的類型,甚至是參數(shù)化接口。一個人為的例子:
type Equaler[T any] interface {
Equals(T) bool
}
type Vector []int32
func (v Vector) Equals(other Vector) bool {
// some logic
}
因此,使用這段代碼,實現(xiàn)Vector了一個特定Equaler的實例。Equaler[Vector]需要明確的是,以下 var 聲明可以編譯:
var _ Equaler[Vector] = Vector{}
因此,有了這個,您可以編寫通用的函數(shù)T并用于T實例化Equaler,并且您將能夠傳遞任何實現(xiàn)該特定實例的東西Equaler:
func Remove[E Equaler[T], T any](es []E, v T) []E {
for i, e := range es {
if e.Equals(v) {
return append(es[:i], es[i+1:]...)
}
}
return es
}
您可以使用 any 調用此函數(shù)T,因此使用T具有Equals(T)方法的 any :
// some other random type that implements Equaler[T]
type MyString string
// implements Equaler[string]
func (s MyString) Equals(other string) bool {
return strings.Split(string(s), "-")[0] == other
}
func main() {
vecs := []Vector{{1, 2}, {3, 4, 5}, {6, 7}, {8}}
fmt.Println(Remove(vecs, Vector{6, 7}))
// prints [[1 2] [3 4 5] [8]]
strs := []MyString{"foo-bar", "hello-world", "bar-baz"}
fmt.Println(Remove(strs, "hello"))
// prints [foo-bar bar-baz]
}
唯一的問題是只有定義的類型才能有方法,所以這種方法已經(jīng)排除了所有復合的非命名類型。
然而,為了部分挽救,Go 具有高階函數(shù),因此使用高階函數(shù)和非命名類型編寫類似流的 API 并非不可能,例如:
func Where[C ~[]T, T any](collection C, predicate func(T) bool) (out C) {
for _, v := range collection {
if predicate(v) {
out = append(out, v)
}
}
return
}
func main() {
// vecs declared earlier
filtered := Where(vecs, func(v Vector) bool { return v[0] == 3})
fmt.Printf("%T %v", filtered, filtered)
// prints []main.Vector [[3 4 5]]
}
特別是在這里你使用命名類型參數(shù)C ~[]T而不是僅僅定義collection []T,這樣你就可以將它用于命名和非命名類型。
操場上可用的代碼:https ://gotipplay.golang.org/p/mCM2TJ9qb3F
(選擇參數(shù)化接口還是高階函數(shù)可能取決于,除其他外,如果你想鏈接方法,但 Go 中的方法鏈接一開始并不是很常見。)
結論:這是否足以模仿 LINQ 或類似 Stream 的 API,和/或啟用大型通用庫,只有實踐才能證明?,F(xiàn)有設施非常強大,在語言設計者獲得泛型實際使用的額外經(jīng)驗后,Go 1.19 中的功能可能會變得更加強大。
- 2 回答
- 0 關注
- 188 瀏覽
添加回答
舉報