当前位置: 首页 > 科技观察

如何让Go的反射更快,你学会了吗?

时间:2023-03-15 17:24:56 科技观察

最近看了一篇关于Go反射的文章。作者使用反射来填充结构体的字段值,充分利用了Go的各种内部机制,逐步讨论让代码运行速度更快的手势。文章(原文地址:https://philpearl.github.io/post/aintnecessarilyslow/)很有学习价值,所以整理了翻译。除非你真的需要,否则不要使用反射。但是当你不用反射的时候,不要以为反射慢,它也可以很快。反射允许您在运行时获取有关Go类型的信息。如果您曾愚蠢地尝试编写新版本的json.Unmarshal,本文将探讨如何使用反射来填充结构值。切入点case我们以一个简单的case作为切入点,定义一个结构体SimpleStruct,它包含两个int类型字段A和B。想要解析它并将字段B设置为42。下面,我们将编写函数来执行此操作,所有这些函数都会将B设置为42。如果我们的代码仅适用于SimpleStruct,这将是完全微不足道的。funcpopulateStruct(in*SimpleStruct){in.B=42}ReflectionBasic但是,如果我们在做一个JSON解析器,这意味着我们无法提前知道结构类型。我们的解析器代码需要接收任何类型的数据。在Go中,这通常意味着采用interface{}(空接口)参数。然后我们可以使用reflect包检查通过空接口参数传入的值,检查它是否是指向结构的指针,找到字段B并用我们的值填充它。代码将如下所示。funcpopulateStructReflect(ininterface{})error{val:=reflect.ValueOf(in)ifval.Type().Kind()!=reflect.Ptr{returnfmt.Errorf("你必须传入一个指针")}elmv:=val.Elem()ifelmv.Type().Kind()!=reflect.Struct{returnfmt.Errorf("youmustpassinapointertoastruct")}fval:=elmv.FieldByName("B")fval.SetInt(42)returnnil}让我们进行基准测试,看看它有多快。funcBenchmarkPopulateReflect(b*testing.B){b.ReportAllocs()varmSimpleStructfori:=0;我