英文:
How to pass a method reference in Go, like in Java?
问题
我正在将我的应用程序从Java重写为Go语言,我知道这两种语言完全不同,包括编程范式,但我还是设法将几乎所有东西都转换过来了。
不幸的是,我在将一个泛型函数作为参数传递给另一个函数时遇到了问题。
在Java中,它看起来像这样:
我有一个接口:
public interface Parser<T> {
public T parse(String line);
}
然后我在一个泛型的fetch
方法中使用这个接口
public static <T> List<T> fetch(Parser<T> parser) {
...
parser.parse(someLine);
...
return the list of generic types
}
然后一个解析方法看起来像这样:
class Parser{
static Foo ParseFoo(String line){
...
一些自定义解析
...
}
}
我像这样使用它:
List<Foo> list = fetch(Parser::ParseFoo);
在Go语言中我该如何实现这个?
我尝试过声明泛型接口、泛型函数,但我无法理解这个问题。
英文:
I'm rewriting my app from Java to Go,
I know the languages are completely different along with paradigms but still I managed to convert nearly everything.
Unfortunately I'm having trouble passing a generic function as an argument to another function.
In Java it looks like this:
I have an interface:
public interface Parser<T> {
public T parse(String line);
}
Then I use this interface in a generic fetch
method
public static <T> List<T> fetch(Parser<T> parser) {
...
parser.parse(someLine);
...
return the list of generic types
}
Then a parser method looks like this:
class Parser{
static Foo ParseFoo(String line){
...
some custom parsing
...
}
}
And I use it like this:
List<Foo> list = fetch(Parser::ParseFoo);
How do I achieve this in Go?
I've tried declaring generic interfaces, generic functions but I can't wrap my head around this.
答案1
得分: 6
一个等效的通用Parser
接口如下所示:
type Parser[T any] interface {
Parse(line string) T
}
任何具有Parse(string) S
方法的类型都会隐式满足Parser[S]
接口。例如,以下类型Foo
满足Parser[int]
:
type Foo struct{}
func (f Foo) Parse(line string) int {
return 0
}
然后,使用通用的Parser
接口,你可以实现通用的Fetch
函数:
func Fetch[T any](parser Parser[T]) []T {
panic("not implemented")
}
传递满足接口的值
在Go中,如何传递类似于Java中的静态方法,比如下面的ParseFoo()
?
class Parser {
static Foo ParseFoo(String line) {
...
}
}
在Go中,没有静态方法。函数可以附加到类型上,这样它们就成为方法。因此,对于在Java中有静态方法的情况,通常会在Go中得到一个非方法函数或独立函数:
func ParseFoo(line string) Foo {
...
}
为了使这个函数满足Parser[Foo]
接口,你可以定义以下ParserFunc
适配器:
type ParserFunc[T any] func(string) T
func (f ParserFunc[T]) Parse(line string) T {
return f(line)
}
这样,从独立函数ParseFoo
(它没有附加到任何类型)中,你可以创建一个ParserFunc[Foo]
的值,它满足Parser[Foo]
,并且在调用其Parse
方法时将调用ParseFoo
:
f := ParserFunc[Foo](ParseFoo)
最后,你可以将这个f
值传递给Fetch
,因为f
满足Parser[Foo]
:
Fetch[Foo](f)
请注意,你需要在fetch
中指定类型参数Foo
,因为编译器无法推断它。
如果你真的需要一个方法(即类似于Java中的非静态/实例方法),那么你可以考虑使用方法值。该过程与此处介绍的过程类似。
英文:
An equivalent generic Parser
interface would look like this:
type Parser[T any] interface {
Parse(line string) T
}
Any type with a Parse(string) S
method will implicitly satisfy the Parser[S]
interface. For example, the following type Foo
satisfies Parser[int]
:
type Foo struct{}
func (f Foo) Parse(string) int {
return 0
}
Then, with the generic Parser
interface, you can implement your generic Fetch
function:
func Fetch[T any](parser Parser[T]) []T {
panic("not implemented")
}
Passing values that satisfy interfaces
How would you then do in Go the equivalent of passing Java static method like ParseFoo()
below?
class Parser {
static Foo ParseFoo(String line) {
...
}
}
In Go, there are no static methods. Functions can be attached to types, in which case they become methods. As such, for the cases when you would have a static method in Java, you would normally end up with a non-method function or standalone function in Go:
func ParseFoo(line string) Foo {
...
}
To make this function satisfy the Parser[Foo]
interface, you can define the following ParserFunc
adapter:
type ParserFunc[T any] func(string) T
func (f ParserFunc[T]) Parse(line string) T {
return f(line)
}
This way, from the standalone function ParseFoo
– which isn't attached to any type – you can create a value of ParserFunc[Foo]
, which does satisfy Parser[Foo]
, and will just call ParseFoo
when its Parse
method is called:
f := ParserFunc[Foo](ParseFoo)
Finally, you can pass this f
value to fetch
since f
satisfies Parser[Foo]
:
fetch[Foo](f)
Note that you need to specify the type argument Foo
to fetch
as the compiler cannot infer it.
If you really need a method (i.e., like a non-static/instance method in Java), then you may want to look at method values. The procedure will be similar to the one exposed here.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论