我是初学者,来自Ruby的土地。
在Ruby中,你可以做这样的事情。
Time.send("now")
相当于Time.now
,因为您要将邮件now
发送到对象Time
golang中有类似的东西吗?
答案 0 :(得分:9)
没有内置的方法可以从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
和MethodByName
的{{1}}包。您还可以查看this Stackoverflow问题。
答案 1 :(得分:6)
正如其他建议的那样,您可以通过将字符串映射到函数来自行完成,但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
,一个用于a
(指向A
的指针)用于方法,一个用于*a
(该领域的A
结构)。尝试使用非指针Value
的指针接收器定义方法(或者相反,尝试通过指针Value
获取字段)将导致恐慌。更一般地说,由于反映的Value
的动态特性及其与通常的类型Go的区别,期望在Value
上不存在许多便利功能(例如自动引用/解除引用)。
此外,在调试时需要相当多的运行时间恐慌,因为这是动态Value
调用失败的唯一方法!
答案 2 :(得分:1)
没有。按照http://tour.golang.org/和http://golang.org/doc/effective_go.html的方式进行操作,您就可以正确理解方法调用的工作原理。
答案 3 :(得分:1)
以下是使用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)
}
}
答案 4 :(得分:0)
我的代码基于发送的this description。
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是动态类型的。通过reflect库支持支持动态类型,但这是一种令人不愉快的体验,而不是一般Go代码的编写方式。