无论接收器类型如何,如何在 Go 中动态调用接口{}上的方法?
动态调用接口上的方法{},无论接收器类型如何
在 Go 的模板系统领域,反射起着至关重要的作用。当动态调用具有不同接收器类型的接口上的方法时,就会出现挑战。{}虽然这可以与已知类型无缝配合,但当数据包装在接口{}中时,它会失败。
问题陈述
考虑以下内容code:
type Test struct { Start string } func (t *Test) Finish() string { return t.Start + "finish" } func Pass(i interface{}) { _, ok := reflect.TypeOf(&i).MethodByName("Finish") if ok { fmt.Println(reflect.ValueOf(&i).MethodByName("Finish").Call([]reflect.Value{})[0]) } else { fmt.Println("Pass() fail") } } func main() { i := Test{Start: "start"} Pass(i) _, ok := reflect.TypeOf(&i).MethodByName("Finish") if ok { fmt.Println(reflect.ValueOf(&i).MethodByName("Finish").Call([]reflect.Value{})[0]) } else { fmt.Println("main() fail") } }
观察
- 当数据是已知类型(main())时,动态方法调用成功。
- 当数据包装在接口{}(Pass())中时,它会失败,第一次返回“Pass()失败”
问题
问题在于当数据包装在接口{}中时访问数据的地址。使用通常指向指针的 &i 在这种情况下不起作用。
解决方案
为了解决这个问题,我们需要处理所有可能的情况:
-
interface{} 数据作为值,方法接收器作为value:
- 如果数据是一个值,则创建一个指向它的指针。
-
interface{} data as作为指针的值和方法接收器:
- 如上所述,创建指向数据的指针。
-
interface{} 数据作为指针,方法接收器作为值:
- 如果数据是指针,则检索它指向的值to.
-
接口{}数据作为指针,方法接收者作为指针:
- 使用指针
实现
基于这个逻辑,我们可以创建一个通用函数来动态调用方法:
func CallMethod(i interface{}, methodName string) interface{} { // Handle all scenarios var ptr, value, finalMethod reflect.Value value = reflect.ValueOf(i) if value.Type().Kind() == reflect.Ptr { ptr = value value = ptr.Elem() } else { ptr = reflect.New(reflect.TypeOf(i)) temp := ptr.Elem() temp.Set(value) } // Check for method on value and pointer method := value.MethodByName(methodName) if method.IsValid() { finalMethod = method } method = ptr.MethodByName(methodName) if method.IsValid() { finalMethod = method } // Call the method if (finalMethod.IsValid()) { return finalMethod.Call([]reflect.Value{})[0].Interface() } // Method not found return "" }
通过此函数,我们现在可以动态调用方法,而不管接收器类型和接口如何{}包装:
i := Test{Start: "start"} j := Test{Start: "start2"} fmt.Println(CallMethod(i, "Finish")) // Output: startfinish fmt.Println(CallMethod(&i, "Finish")) // Output: startfinish fmt.Println(CallMethod(i, "Another")) // Output: fmt.Println(CallMethod(&i, "Another")) // Output: start2another fmt.Println(CallMethod(j, "Finish")) // Output: startfinish fmt.Println(CallMethod(&j, "Finish")) // Output: start2finish fmt.Println(CallMethod(j, "Another")) // Output: fmt.Println(CallMethod(&j, "Another")) // Output: start2another
以上是无论接收器类型如何,如何在 Go 中动态调用接口{}上的方法?的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

本文演示了创建模拟和存根进行单元测试。 它强调使用接口,提供模拟实现的示例,并讨论最佳实践,例如保持模拟集中并使用断言库。 文章

本文探讨了GO的仿制药自定义类型约束。 它详细介绍了界面如何定义通用功能的最低类型要求,从而改善了类型的安全性和代码可重复使用性。 本文还讨论了局限性和最佳实践

本文使用跟踪工具探讨了GO应用程序执行流。 它讨论了手册和自动仪器技术,比较诸如Jaeger,Zipkin和Opentelemetry之类的工具,并突出显示有效的数据可视化

本文讨论了GO的反思软件包,用于运行时操作代码,对序列化,通用编程等有益。它警告性能成本,例如较慢的执行和更高的内存使用,建议明智的使用和最佳

本文讨论了GO中使用表驱动的测试,该方法使用测试用例表来测试具有多个输入和结果的功能。它突出了诸如提高的可读性,降低重复,可伸缩性,一致性和A

本文讨论了通过go.mod,涵盖规范,更新和冲突解决方案管理GO模块依赖关系。它强调了最佳实践,例如语义版本控制和定期更新。
