随着Go 1.18中泛型的增加,现在是否有可能提出一个相当于C#的LINQ to Objects的东西?
或者说,与C#泛型相比,Go的泛型在原则上缺乏一些东西,这会使它变得困难或不可能?
例如,最初的101个LINQ样本中的第一个(“LowNumbers”)现在可以在Go中使用泛型实现,大致如下所示:
package main
import (
"fmt"
)
type collection[T comparable] []T
func (input collection[T]) where(pred func(T) bool) collection[T] {
result := collection[T]{}
for _, j := range input {
if pred(j) {
result = append(result, j)
}
}
return result
}
func main() {
numbers := collection[int]{5, 4, 1, 3, 9, 8, 6, 7, 2, 0}
lowNums := numbers.where(func(i int) bool { return i < 5 })
fmt.Println("Numbers < 5:")
fmt.Println(lowNums)
}
3条答案
按热度按时间cld4siwp1#
是也不是
你几乎可以使用一个链接的API到达那里。这适用于许多标准LINQ方法,如
Skip
,Take
,Where
,First
,Last
等。不起作用的是,当你需要切换到流/流中的另一个泛型类型时。
Go Generics不允许 * 方法 * 拥有除了接口/结构之外的其他类型参数。例如,你不能有一个结构
Foo[T any]
,然后有一个方法Bar[O any]
这是需要的方法,如Select
,你有一个类型的输入和另一个类型的输出。但是,如果你不使用链接,只使用普通函数。那么你就可以得到非常接近的功能。
我在这里做过:https://github.com/asynkron/gofun
这是一个通过模拟协同例程实现的完全惰性可枚举实现。
这里不起作用的是像
Zip
这样的函数,它需要同时枚举两个枚举。(虽然有办法破解它。(Nothing Pretty)rqdpfwrv2#
(免责声明:我不是C#Maven)
Go语言的参数多态性与C#或Java中泛型的实现之间的一个显著区别是Go语言(仍然)没有类型参数的协/反方差语法。
例如,在C#中,您可以使用实现
IComparer<T>
并传递派生容器类的代码;或者Java中典型的Predicate<? super T>
流API。在Go语言中,类型必须完全匹配,并且用不同的类型参数示例化泛型类型会产生不同的命名类型,而这些类型只是不能相互赋值。标签:Why does Go not allow assigning one generic to another?Go不是OO,所以没有继承的概念。您可能有实现接口的类型,甚至参数化接口。一个人为的例子:
因此,通过这段代码,
Vector
实现了**Equaler
的特定示例**,即Equaler[Vector]
。为了清楚起见,编译以下var声明:因此,您可以编写
T
中的泛型函数,并使用T
示例化Equaler
,并且您将能够传递任何实现Equaler
特定示例的函数:你可以用任何
T
调用这个函数,也可以用任何Equals(T)
方法的T
调用这个函数:唯一的问题是只有定义的类型才能有方法,所以这种方法已经排除了所有复合的非命名类型。
然而,为了部分补救,Go语言具有更高阶的函数,因此使用该类型和非命名类型编写类似流的API并非不可能,例如:
特别是在这里,您使用命名类型参数
C ~[]T
,而不是仅仅定义collection []T
,这样您就可以同时使用命名类型和非命名类型。Playground可用代码:https://gotipplay.golang.org/p/mCM2TJ9qb3F
(选择参数化接口与高阶函数可能取决于,如果你想链接方法,但在Go语言中方法链接并不常见。
结论:这是否足以模仿LINQ或Stream-like API,和/或启用大型通用库,只有实践才能说明问题。现有的功能非常强大,在语言设计者获得了泛型的真实使用经验之后,Go 1.19中可能会变得更加强大。
wbgh16ku3#
Go泛型目前不支持泛型方法。但是你可以编写泛型函数。
你可以在我的存储库中获得Filter()和许多其他有用的工具函数:https://github.com/szmcdull/glinq