我是一名围棋初学者,来自 Ruby 大陆。
在 Ruby 中,你可以做这样的事情。
Time.send("now")
相当于Time.now
, 因为您正在向now
对象发送消息Time
golang中是否有类似的东西?
我是一名围棋初学者,来自 Ruby 大陆。
在 Ruby 中,你可以做这样的事情。
Time.send("now")
相当于Time.now
, 因为您正在向now
对象发送消息Time
golang中是否有类似的东西?
Go 中没有内置的从字符串调用任意函数的方法。
您可以通过将函数注册到 map[string] 来创建类似的东西。一个工作示例:
package main
import "fmt"
var m = map[string]func(){
"now": func() { fmt.Println("The time is now") },
"then": func() { fmt.Println("Once upon a time") },
}
func main() {
cmd := "then"
m[cmd]()
}
也可以使用反射来按名称调用方法。您可以查看 和的reflect
包装。您还可以查看这个Stackoverflow 问题。MethodByName
Call
正如其他人建议的那样,您可以通过将字符串映射到函数来自己完成,但是 Go 的强类型特性使得.send
直接翻译成 Go 变得很困难。
如果您确实需要按名称访问字段或方法,您仍然可以使用反射:
import "reflect"
import "fmt"
type A struct {
Number int
}
func (a *A) Method(i int) int {
return a.Number + i;
}
func main() {
a := &A{Number: 1}
// Direct access
fmt.Printf("Direct -> Nb: %d, Nb + 2: %d\n", a.Number, a.Method(2));
v := reflect.ValueOf(*a)
vp := reflect.ValueOf(a)
field := v.FieldByName("Number")
meth := vp.MethodByName("Method")
args := []reflect.Value{reflect.ValueOf(2)}
// Reflection access
fmt.Printf("Reflect -> Nb: %d, Nb + 2: %d\n",
field.Interface().(int),
meth.Call(args)[0].Interface().(int))
}
输出:
Direct -> Nb: 1, Nb + 2: 3
Reflect -> Nb: 1, Nb + 2: 3
但请注意:
使用reflect
包将您的类型变量更改为更灵活Value
的对象,但这些在实践中使用起来非常麻烦。如果你能找到一种不依赖反思的方式来表达你的意图,通常会更好。
还要注意,在这里,我们必须使用两个Value
s,一个用于a
(指向 的指针A
)用于方法,一个用于*a
(A
结构)用于字段。尝试使用带有非指针的指针接收器定义的方法Value
(或者相反,尝试通过指针获取字段Value
)将导致恐慌。更一般地说,由于反射Value
s 的动态特性及其与通常类型化的 Go 的区别,预计 s 上不存在许多便利功能(例如自动引用/取消引用)Value
。
此外,调试时会出现相当多的运行时恐慌,因为这是动态Value
调用失败的唯一方法!
参考:反射包
不会。通过http://tour.golang.org/和http://golang.org/doc/effective_go.html工作,您将正确理解方法调用的工作原理。
这是一个使用的工作示例reflect
package main
import (
"fmt"
"os"
"reflect"
)
// Send sends a message to(calls a method of) obj, with args.
// The return value of the method call is set to ret and any error to err.
func Send(obj interface{}, method string, args ...interface{}) (ret []reflect.Value, err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("%v", e)
}
}()
objValue := reflect.ValueOf(obj)
argsValue := make([]reflect.Value, 0, len(args))
for _, arg := range args {
argsValue = append(argsValue, reflect.ValueOf(arg))
}
mtd := objValue.MethodByName(method)
if !mtd.IsValid() {
return nil, fmt.Errorf("%v does not have a method %v", reflect.TypeOf(obj), method)
}
ret = mtd.Call(argsValue)
return
}
// Then do some tests.
type A struct {
value int
}
func (a A) Value() int {
return a.value
}
func (a *A) SetValue(v int) {
a.value = v
}
func main() {
var (
ret []reflect.Value
err error
)
// StdOut.WriteString("Hello, World!\n")
_, err = Send(os.Stdout, "WriteString", "Hello, World!\n")
handleError(err)
var a = &A{100}
// ret = a.Value()
ret, err = Send(a, "Value")
handleError(err)
fmt.Printf("Return value is: %v\n", ret[0].Int())
// a.SetValue(200)
_, err = Send(a, "SetValue", 200)
handleError(err)
// ret = a.Value()
ret, err = Send(a, "Value")
handleError(err)
fmt.Printf("Return value is: %v", ret[0].Int())
}
func handleError(err error) {
if err != nil {
panic(err)
}
}
我的代码基于发送的这个描述。
class Klass
def hello(*args)
"Hello " + args.join(' ')
end
end
k = Klass.new
k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
http://play.golang.org/p/lXlzBf_fGZ
package main
import "strings"
type Klass struct{}
func (k Klass) Hello(args ...string) string {
return "Hello " + strings.Join(args, " ")
}
func (k Klass) Send(symbol func(Klass, ...string) string, args ...string) string {
return symbol(k, args...)
}
func main() {
k := new(Klass)
k.Send(Klass.Hello, "gentle", "readers") //=> "Hello gentle readers"
}
两者最大的区别在于,Go 的Send
函数仅用于Klass
并且仅适用于将可变数量的字符串作为参数并返回单个字符串的方法。这是因为 Go 是一种静态类型语言,其中 Ruby 是动态类型的。Go确实通过反射库支持动态类型,但这是一种不愉快的体验,而不是一般 Go 代码的编写方式。