Go中的方法图

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

Map of methods in Go

问题

我有几个方法,我在某些情况下调用它们(比如Add,Delete等)。然而,随着时间的推移,情况的数量正在增加,我的switch-case语句变得越来越长。所以我想创建一个方法的映射,就像https://stackoverflow.com/questions/6769020/go-map-of-functions中的那样;这里的函数映射是微不足道的。然而,在Go中是否可以创建一个方法的映射呢?

当我们有一个方法:

func (f *Foo) Add(a string, b int) { }

下面的语法会产生编译时错误:

actions := map[string]func(a, b){
    "add": f.Add(a,b),
}

在Go中是否可以创建一个方法的映射呢?

英文:

I have several methods that I'm calling for some cases (like Add, Delete, etc..). However over time the number of cases is increasing and my switch-case is getting longer. So I thought I'd create a map of methods, like https://stackoverflow.com/questions/6769020/go-map-of-functions; here the mapping of functions is trivial. However, is it possible to create a map of methods in Go?

When we have a method:

func (f *Foo) Add(a string, b int) { }

The syntax below create compile-time error:

actions := map[string]func(a, b){
		"add": f.Add(a,b),
}

Is it possible to create a map of methods in Go?

答案1

得分: 11

是的。目前:

actions := map[string]func(a string, b int){
        "add": func(a string, b int) { f.Add(a, b) },
}

以后:参见guelfi提到的go11func文档。

英文:

Yes. Currently:

actions := map[string]func(a string, b int){
        "add": func(a string, b int) { f.Add(a, b) },
}

Later: see the go11func document guelfi mentioned.

答案2

得分: 3

目前没有办法将接收器和方法存储在单个值中(除非将其存储在结构体中)。目前正在处理此问题,并且可能会在Go 1.1中进行更改(请参阅http://golang.org/s/go11func)。

但是,您可以将方法分配给一个函数值(没有接收器),然后稍后将接收器传递给该值:

package main

import "fmt"

type Foo struct {
    n int
}

func (f *Foo) Bar(m int) int {
    return f.n + m
}

func main() {
    foo := &Foo{2}
    f := (*Foo).Bar
    fmt.Printf("%T\n", f)
    fmt.Println(f(foo, 42))
}

这个值可以像其他任何东西一样存储在map中。

英文:

There is currently no way to store both receiver and method in a single value (unless you store it in a struct). This is currently worked on and it may change with Go 1.1 (see http://golang.org/s/go11func).

You may, however, assign a method to a function value (without a receiver) and pass the receiver to the value later:

package main

import "fmt"

type Foo struct {
    n int
}

func (f *Foo) Bar(m int) int {
	return f.n + m
}

func main() {
	foo := &Foo{2}
	f := (*Foo).Bar
	fmt.Printf("%T\n", f)
	fmt.Println(f(foo, 42))
}

This value can be stored in a map like anything else.

答案3

得分: 1

我遇到了一个类似的问题。

9年后,今天如何解决这个问题:

问题在于接收器必须作为第一个参数传递给map方法。这相当不寻常。

package main

import (
	"fmt"
	"log"
)

type mType struct {
	str string
}

func (m *mType) getStr(s string) {
	fmt.Println(s)
	fmt.Println(m.str)
}

var (
	testmap = make(map[string]func(m *mType, s string))
)

func main() {
	test := &mType{
		str: "Internal string",
	}
	testmap["GetSTR"] = (*mType).getStr
	method, ok := testmap["GetSTR"]
	if !ok {
		log.Fatal("something goes wrong")
	}
	method(test, "External string")
}

https://go.dev/play/p/yy3aR_kMzHP

英文:

I met with a similar question.

How can this be done today, 9 years later:

the thing is that the receiver must be passed to the method map as the first argument. Which is pretty unusual.

package main

import (
	"fmt"
	"log"
)

type mType struct {
	str string
}

func (m *mType) getStr(s string) {
	fmt.Println(s)
	fmt.Println(m.str)
}

var (
	testmap = make(map[string]func(m *mType, s string))
)

func main() {
	test := &mType{
		str: "Internal string",
	}
	testmap["GetSTR"] = (*mType).getStr
	method, ok := testmap["GetSTR"]
	if !ok {
		log.Fatal("something goes wrong")
	}
	method(test, "External string")
}

https://go.dev/play/p/yy3aR_kMzHP

答案4

得分: 0

你可以使用方法表达式来实现这个:

https://golang.org/ref/spec#Method_expressions

然而,这会使函数将接收器作为第一个参数:

actions := map[string]func(Foo, string, int){
  "add": Foo.Add
}

同样地,你可以使用(*Foo).Add来获取一个具有签名func(*Foo, string, int)的函数。

英文:

You can do this using Method Expressions:

https://golang.org/ref/spec#Method_expressions

However, this makes the function take the receiver as a first argument:

actions := map[string]func(Foo, string, int){
  "add": Foo.Add
}

Similarly, you can get a function with the signature func(*Foo, string, int) using (*Foo).Add

答案5

得分: 0

如果你想使用指向类型Foo的指针作为接收器,就像这样:

func (f *Foo) Add(a string, b int) { }

那么你可以将字符串映射到(*Foo, string, int)类型的函数,像这样:

var operations = map[string]func(*Foo, string, int){
    "add": (*Foo).Add,
    "delete": (*Foo).Delete,
}

然后你可以这样使用它:

var foo Foo = ...
var op string = GetOp() // "add", "delete", ...
operations[op](&foo, a, b)

其中GetOp()返回一个字符串操作,例如来自用户输入。
ab是你方法的字符串和整数参数。

这假设所有方法具有相同的签名。它们也可以有返回值,返回值类型也相同。

也可以将Foo作为接收器来实现这一点,而不是*Foo。在这种情况下,我们在映射中不需要解引用它,并且我们传递foo而不是&foo

英文:

If you want to use pointer to type Foo as receiver, like in:

func (f *Foo) Add(a string, b int) { }

then you can map string to function of (*Foo, string, int), like this:

var operations = map[string]func(*Foo, string, int){
    "add": (*Foo).Add,
    "delete": (*Foo).Delete,
}

Then you would use it as:

var foo Foo = ...
var op string = GetOp() // "add", "delete", ...
operations[op](&foo, a, b)

where GetOp() returns an operation as string, for example from a user input.
a and b are your string and int arguments to methods.

This assumes that all methods have the same signatures. They can also have return value(s), again of the same type(s).

It is also possible to do this with Foo as receiver instead of *Foo. In that case we don't have to de-reference it in the map, and we pass foo instead of &foo.

huangapple
  • 本文由 发表于 2013年2月26日 21:13:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/15090037.html
匿名

发表评论

匿名网友

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

确定