• 如何让 Go 反射变快,你学会了吗?


    最近读到一篇关于 Go 反射的文章,作者通过反射给结构体填充字段值的案例,充分利用 Go 的各种内在机理,逐步探讨让代码运行得更快的姿势。

    文章(原文地址:https://philpearl.github.io/post/aintnecessarilyslow/)非常有学习价值,故翻译整理了下来。

    不要使用反射,除非你真的需要。但是当你不使用反射时,不要认为这是因为反射很慢,它也可以很快。

    反射允许你在运行时获得有关 Go 类型的信息。如果你曾经愚蠢地尝试编写 json.Unmarshal 之类的新版本,本文将探讨的就是如何使用反射来填充结构体值。

    切入点案例

    我们以一个简单的案例为切入点,定义一个结构体 SimpleStruct,它包括两个 int 类型字段 A 和 B。

    type SimpleStruct struct {
        A int
        B int
    }

    假如我们接收到了 JSON 数据 {"B": 42},想要对其进行解析并且将字段 B 设置为 42。

    在下文,我们将编写一些函数来实现这一点,它们都会将 B 设置为 42。

    如果我们的代码只适用于 SimpleStruct,这完全是不值一提的。

    func populateStruct(in *SimpleStruct) {
        in.B = 42
    }

    反射基本版

    但是,如果我们是要做一个 JSON 解析器,这意味着我们并不能提前知道结构类型。我们的解析器代码需要接收任何类型的数据。

    在 Go 中,这通常意味着需要采用 interface{} (空接口)参数。然后我们可以使用 reflect 包检查通过空接口参数传入的值,检查它是否是指向结构体的指针,找到字段 B 并用我们的值填充它。

    代码将如下所示。

    func populateStructReflect(in interface{}) error {
     val := reflect.ValueOf(in)
     if val.Type().Kind() != reflect.Ptr {
      return fmt.Errorf("you must pass in a pointer")
     }
     elmv := val.Elem()
     if elmv.Type().Kind() != reflect.Struct {
      return fmt.Errorf("you must pass in a pointer to a struct")
     }
    
     fval := elmv.FieldByName("B")
     fval.SetInt(42)
    
     return nil
    }

    让我们通过基准测试看看它有多快。

    func BenchmarkPopulateReflect(b *testing.B) {
     b.ReportAllocs()
     var m SimpleStruct
     for i := 0; i < b.N; i++ {
      if err := populateStructReflect(&am
  • 相关阅读:
    开源了 | 文心大模型ERNIE-Tiny轻量化技术,又准又快,效果全开
    车载Camera术语大全
    SIMetrix导入MOS管参数的另一种方法
    all in one 部署
    结构体数组保存进二进制文件的简单做法
    Bandizip去除广告,注册图标,状态栏文本
    【Java练习生】每日面试题学习打卡!
    CSS设置盒子阴影
    【密码学篇】(商密)密码算法分析理论知识
    POJ 1328 Radar Installation 贪心算法
  • 原文地址:https://blog.csdn.net/m0_73257876/article/details/126578264