How to pass a method reference in Go, like in Java?

huangapple go评论116阅读模式
英文:

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&lt;T&gt; {
    public T parse(String line);
}

Then I use this interface in a generic fetch method

public static &lt;T&gt; List&lt;T&gt; fetch(Parser&lt;T&gt; 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&lt;Foo&gt; 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(&quot;not implemented&quot;)
}

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.

huangapple
  • 本文由 发表于 2023年5月27日 15:45:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/76345860.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定