php小编柚子在golang中,使用method.Call方法调用函数时,对于数字类型参数可能会遇到一些问题。但是,我们可以采用一些方法来解决这个问题。首先,我们可以将数字类型转换为对应的reflect.Value类型,然后再传递给method.Call方法。另外,我们还可以使用反射方法来获取函数的参数类型,并根据参数类型进行相应的处理。总之,通过这些方法,我们可以使数字类型适合golang中的method.Call方法的调用,从而解决这个问题。
问题内容
代码围棋游乐场:
package main
import (
"fmt"
"reflect"
)
func (s StructWithManyMethods) Func1(a int, b uint, c float64) {
fmt.Printf("func:Func1 a:%d b:%d c:%f \n", a, b, c)
}
func (s StructWithManyMethods) Func2(a string, b int, c int, d int) {
fmt.Printf("func:Func2 a:%s b:%d c:%d d:%d\n", a, b, c, d)
}
type StructWithManyMethods struct {
}
func (s StructWithManyMethods) CallMethod(n string, p []interface{}) {
method := reflect.ValueOf(s).MethodByName(n)
methodType := method.Type()
for i := 0; i < methodType.NumIn(); i++ {
in := methodType.In(i)
switch in.Kind() {
case reflect.Float32:
switch v := p[i].(type) {
case float64:
p[i] = float32(v)
case float32:
p[i] = float32(v)
case int:
p[i] = float32(v)
case uint:
p[i] = float32(v)
case int8:
p[i] = float32(v)
case uint8:
p[i] = float32(v)
case int16:
p[i] = float32(v)
case uint16:
p[i] = float32(v)
case int32:
p[i] = float32(v)
case uint32:
p[i] = float32(v)
case int64:
p[i] = float32(v)
case uint64:
p[i] = float32(v)
}
case reflect.Float64:
switch v := p[i].(type) {
case float64:
p[i] = float64(v)
case float32:
p[i] = float64(v)
case int:
p[i] = float64(v)
case uint:
p[i] = float64(v)
case int8:
p[i] = float64(v)
case uint8:
p[i] = float64(v)
case int16:
p[i] = float64(v)
case uint16:
p[i] = float64(v)
case int32:
p[i] = float64(v)
case uint32:
p[i] = float64(v)
case int64:
p[i] = float64(v)
case uint64:
p[i] = float64(v)
}
case reflect.Int:
switch v := p[i].(type) {
case float64:
p[i] = int(v)
case float32:
p[i] = int(v)
case int:
p[i] = int(v)
case uint:
p[i] = int(v)
case int8:
p[i] = int(v)
case uint8:
p[i] = int(v)
case int16:
p[i] = int(v)
case uint16:
p[i] = int(v)
case int32:
p[i] = int(v)
case uint32:
p[i] = int(v)
case int64:
p[i] = int(v)
case uint64:
p[i] = int(v)
}
case reflect.Uint:
switch v := p[i].(type) {
case float64:
p[i] = uint(v)
case float32:
p[i] = uint(v)
case int:
p[i] = uint(v)
case uint:
p[i] = uint(v)
case int8:
p[i] = uint(v)
case uint8:
p[i] = uint(v)
case int16:
p[i] = uint(v)
case uint16:
p[i] = uint(v)
case int32:
p[i] = uint(v)
case uint32:
p[i] = uint(v)
case int64:
p[i] = uint(v)
case uint64:
p[i] = uint(v)
}
case reflect.Int8:
switch v := p[i].(type) {
case float64:
p[i] = int8(v)
case float32:
p[i] = int8(v)
case int:
p[i] = int8(v)
case uint:
p[i] = int8(v)
case int8:
p[i] = int8(v)
case uint8:
p[i] = int8(v)
case int16:
p[i] = int8(v)
case uint16:
p[i] = int8(v)
case int32:
p[i] = int8(v)
case uint32:
p[i] = int8(v)
case int64:
p[i] = int8(v)
case uint64:
p[i] = int8(v)
}
case reflect.Uint8:
switch v := p[i].(type) {
case float64:
p[i] = uint8(v)
case float32:
p[i] = uint8(v)
case int:
p[i] = uint8(v)
case uint:
p[i] = uint8(v)
case int8:
p[i] = uint8(v)
case uint8:
p[i] = uint8(v)
case int16:
p[i] = uint8(v)
case uint16:
p[i] = uint8(v)
case int32:
p[i] = uint8(v)
case uint32:
p[i] = uint8(v)
case int64:
p[i] = uint8(v)
case uint64:
p[i] = uint8(v)
}
case reflect.Int16:
switch v := p[i].(type) {
case float64:
p[i] = int16(v)
case float32:
p[i] = int16(v)
case int:
p[i] = int16(v)
case uint:
p[i] = int16(v)
case int8:
p[i] = int16(v)
case uint8:
p[i] = int16(v)
case int16:
p[i] = int16(v)
case uint16:
p[i] = int16(v)
case int32:
p[i] = int16(v)
case uint32:
p[i] = int16(v)
case int64:
p[i] = int16(v)
case uint64:
p[i] = int16(v)
}
case reflect.Uint16:
switch v := p[i].(type) {
case float64:
p[i] = uint16(v)
case float32:
p[i] = uint16(v)
case int:
p[i] = uint16(v)
case uint:
p[i] = uint16(v)
case int8:
p[i] = uint16(v)
case uint8:
p[i] = uint16(v)
case int16:
p[i] = uint16(v)
case uint16:
p[i] = uint16(v)
case int32:
p[i] = uint16(v)
case uint32:
p[i] = uint16(v)
case int64:
p[i] = uint16(v)
case uint64:
p[i] = uint16(v)
}
case reflect.Int32:
switch v := p[i].(type) {
case float64:
p[i] = int32(v)
case float32:
p[i] = int32(v)
case int:
p[i] = int32(v)
case uint:
p[i] = int32(v)
case int8:
p[i] = int32(v)
case uint8:
p[i] = int32(v)
case int16:
p[i] = int32(v)
case uint16:
p[i] = int32(v)
case int32:
p[i] = int32(v)
case uint32:
p[i] = int32(v)
case int64:
p[i] = int32(v)
case uint64:
p[i] = int32(v)
}
case reflect.Uint32:
switch v := p[i].(type) {
case float64:
p[i] = uint32(v)
case float32:
p[i] = uint32(v)
case int:
p[i] = uint32(v)
case uint:
p[i] = uint32(v)
case int8:
p[i] = uint32(v)
case uint8:
p[i] = uint32(v)
case int16:
p[i] = uint32(v)
case uint16:
p[i] = uint32(v)
case int32:
p[i] = uint32(v)
case uint32:
p[i] = uint32(v)
case int64:
p[i] = uint32(v)
case uint64:
p[i] = uint32(v)
}
case reflect.Int64:
switch v := p[i].(type) {
case float64:
p[i] = int64(v)
case float32:
p[i] = int64(v)
case int:
p[i] = int64(v)
case uint:
p[i] = int64(v)
case int8:
p[i] = int64(v)
case uint8:
p[i] = int64(v)
case int16:
p[i] = int64(v)
case uint16:
p[i] = int64(v)
case int32:
p[i] = int64(v)
case uint32:
p[i] = int64(v)
case int64:
p[i] = int64(v)
case uint64:
p[i] = int64(v)
}
case reflect.Uint64:
switch v := p[i].(type) {
case float64:
p[i] = uint64(v)
case float32:
p[i] = uint64(v)
case int:
p[i] = uint64(v)
case uint:
p[i] = uint64(v)
case int8:
p[i] = uint64(v)
case uint8:
p[i] = uint64(v)
case int16:
p[i] = uint64(v)
case uint16:
p[i] = uint64(v)
case int32:
p[i] = uint64(v)
case uint32:
p[i] = uint64(v)
case int64:
p[i] = uint64(v)
case uint64:
p[i] = uint64(v)
}
}
}
parameterValues := make([]reflect.Value, 0)
for _, e := range p {
parameterValues = append(parameterValues, reflect.ValueOf(e))
}
method.Call(parameterValues)
}
func main() {
var s StructWithManyMethods
s.CallMethod("Func1", []interface{}{1.0, 2.0, 3})
s.CallMethod("Func2", []interface{}{"test", 1, 2, 3.0})
}
输出:
func:Func1 a:1 b:2 c:3.000000
func:Func2 a:test b:1 c:2 d:3
因为我需要动态调用方法,但是参数来自不同的数据格式,这就导致需要转换数值类型。例如,在Golang中解析JSON时,不确定的数字类型被视为float64,尽管它可能应该是int。
代码看起来很糟糕,但运行良好。
我想知道是否有更好的方法来做到这一点。
解决方法
使用reflect API 转换值。
func (s StructWithManyMethods) CallMethod(n string, p []interface{}) error {
method := reflect.ValueOf(s).MethodByName(n)
methodType := method.Type()
parameterValues := make([]reflect.Value, methodType.NumIn())
if len(p) < len(parameterValues) {
return fmt.Errorf("expected %d parameters, got %d", len(parameterValues), len(p))
}
for i := range parameterValues {
in := methodType.In(i)
v := reflect.ValueOf(p[i])
if !v.CanConvert(in) {
return fmt.Errorf("cannot convert p[%d] from %s to %s", i, v.Type(), in)
}
parameterValues[i] = reflect.ValueOf(p[i]).Convert(in)
}
method.Call(parameterValues)
return nil
}
为了防止出现恐慌,此代码在转换之前检查是否允许转换。
在 PlayGround 上运行代码!
以上就是有没有好的方法让数字类型适合golang中的“method.Call”?的详细内容,更多请关注编程网其它相关文章!