学会提升Go语言编码效率技巧拒绝加班!

 更新时间:2023年12月19日 10:58:11   作者:Go语言圈 磊丰  
这篇文章主要为大家介绍了Go语言编码效率提升技巧详解,学会了从此拒绝加班,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

在Go语言中,`slice`和`map`是我们常用的基础类型,通过它们,我们可以轻松地处理数据。然而,你可能会注意到,为了处理这两种数据,我们不得不编写许多实用函数。

比如,从`slice`切片中查找一个元素的位置。而这种查找又分为从前查找和从后查找。又或者,获取`map`的所有键?或者所有的值?

再比如,在JavaScript中,数组的`map`、`reduce`、`filter`等函数非常好用,但是令人遗憾的是,Go标准库没有提供这样的功能。

这些例子还有很多,而且都是我们在编程中经常需要的实用函数。但是,我们的Go SDK并没有提供这些。

那么我们应该怎么办呢?

一种方法是自己编写一个工具包,供项目使用,但是这个工具包的维护可能会成为一个问题,需要投入人力。

go-funk

第二种方式是使用开源库,经过充分的测试、验证,并且经常更新,以确保可用性。

因为我们遇到的是常见问题,所以一些人已经做了开源库,以供大家使用。

这样的工具库以Go 1.18为分界线,Go 1.18之前比较有名的是`go-funk`。

它有一个有趣的名字Repo

地址是 https://github.com/thoas/go-funk

它被官方介绍为一个现代化的Go实用工具库:

"A modern Go utility library which provides helpers (map, find, contains, filter, ...)"

它提供了许多实用的函数,比如`Contains`、`Difference`、`IndexOf`、`LastIndexOf`等等,具体更多的可以参考它的文档。

然而,它有一个致命的问题,就是使用了反射。这也是无法避免的,因为在Go泛型没有支持之前,只能通过反射来编写满足不同类型的函数。

举个例子,如果不使用反射,要想支持更多的类型,就得定义很多相似名称的函数,如下所示:

func IndexOfBool(a []bool, x bool) int {
}
func IndexOfInt(a []int, x int) int {
}
func IndexOfInt32(a []int32, x int32) int {
}
func IndexOfInt64(a []int64, x int64) int {
}
func IndexOfUInt(a []uint, x uint) int {
}
func IndexOfUInt32(a []uint32, x uint32) int {
}
func IndexOfUInt64(a []uint64, x uint64) int {
}
func IndexOfFloat64(a []float64, x float64) int {
}
func IndexOfString(a []string, x string) int {
}

以上函数行不行?当然行,但是会写很多重复的代码,并且看着也怪怪的。

在Go语言的泛型支持之前,要解决这个问题,只能通过反射。

在Go语言的泛型支持之前,处理slice和map的通用工具函数通常需要使用反射。

虽然这种方法可以帮助我们编写更通用的代码,但也会带来一些性能开销。

例如,考虑一个通用的查找函数,用于在切片中查找特定的元素:

go
Copy code
import (
    "reflect"
)
func indexOf(slice interface{}, target interface{}) int {
    sliceValue := reflect.ValueOf(slice)
    for i := 0; i < sliceValue.Len(); i++ {
        element := sliceValue.Index(i).Interface()
        if element == target {
            return i
        }
    }
    return -1
}

上述函数使用了反射,它能够接受任意类型的切片,并在其中查找目标元素。然而,这种灵活性是以性能为代价的,因为反射的开销相对较高。

在Go 1.18引入泛型之前,我们不得不在不同类型的切片和映射上编写类似的通用函数,这可能会导致很多重复的代码。在实际应用中,我们需要权衡代码的通用性和性能开销。

值得注意的是,Go语言的泛型支持已经提供了更为优雅和高效的解决方案,可以在不使用反射的情况下实现通用性。

使用泛型编写更直观且类型安全的通用函数

在Go 1.18及以后的版本中,你可以使用泛型编写更直观且类型安全的通用函数。

// IndexOf gets the index at which the first occurrence
// of value is found in array or return -1
// if the value cannot be found
func IndexOf(in interface{}, elem interface{}) int {
  inValue := reflect.ValueOf(in)
  elemValue := reflect.ValueOf(elem)
  inType := inValue.Type()
  if inType.Kind() == reflect.String {
    return strings.Index(inValue.String(), elemValue.String())
  }
  if inType.Kind() == reflect.Slice {
    equalTo := equal(elem)
    for i := 0; i < inValue.Len(); i++ {
      if equalTo(reflect.Value{}, inValue.Index(i)) {
        return i
      }
    }
  }
  return -1
}

泛型代码复杂,并且效率低。。。

那么Go 1.18之后已经支持了泛型,能不能用泛型来重写呢?

答案是:当然可以,并且已经有人这么做了。这个库就是 https://github.com/samber/lo

IndexOf函数实现

它是基于Go泛型实现,没有用到反射,效率高,代码简洁。比如刚刚的IndexOf函数,在该库中是这么实现的:

// IndexOf returns the index at which the first occurrence of
// a value is found in an array or return -1
// if the value cannot be found.
func IndexOf[T comparable](collection []T, element T) int {
  for i, item := range collection {
    if item == element {
      return i
    }
  }

  return -1
}

只需要 T 被约束为comparable 的,就可以使用==符号进行比较了,整体代码非常简单,并且没有反射。

IndexOf只是lo几十个函数中的一个,这些函数基本上覆盖了slice、map、string等方方面面,涉及查找、比较大小、生成、map、reduce、过滤、填充、反转、分组等等,使用方法和示例,可以参考go doc文档

以上就是学会提升Go语言编码效率技巧拒绝加班!的详细内容,更多关于Go语言编码效率提升的资料请关注脚本之家其它相关文章!

相关文章

  • Go语言类型转换的方式有哪些

    Go语言类型转换的方式有哪些

    本文主要介绍了Go语言类型转换的方式有哪些,类型转换主要有4种,分别为断言类型转换、显式类型转换、隐式类型转换、强制类型转换,感兴趣的可以了解一下
    2023-11-11
  • Go 语言中的指针的使用

    Go 语言中的指针的使用

    在Go语言中,指针是存储另一变量内存地址的变量,通过&操作符获取变量地址,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-09-09
  • Golang reflect反射的使用实例

    Golang reflect反射的使用实例

    Golang反射的错误大多数都来自于调用了一个不适合当前类型的方法,而且,这些错误通常是在运行时才会暴露出来,而不是在编译时,如果我们传递的类型在反射代码中没有被覆盖到那么很容易就会panic,本文就介绍一下使用go反射时很大概率会出现的错误,需要的可以参考一下
    2023-04-04
  • golang实现RPC模块的示例

    golang实现RPC模块的示例

    本文详细介绍了在Go语言中如何实现RPC模块,包括RPC服务端和客户端的构建及代码实现,同时提到了使用JSON-RPC的方法,通过简单的步骤,可以实现跨进程的远程过程调用,感兴趣的可以了解一下
    2024-09-09
  • golang中单向channel的语法介绍

    golang中单向channel的语法介绍

    通过消息来共享数据是golang的一种设计哲学,channel则是这种哲理的体现。下面这篇文章主要给大家介绍了关于golang中单向channel语法的相关资料,文中通过示例代码介绍的非常详细,需要的朋友们下面来一起看看吧。
    2017-07-07
  • go语言中json处理方式详解

    go语言中json处理方式详解

    这篇文章主要介绍了go语言中json处理方式,文中通过实例代码讲解的非常详细,对大家的学习或工作有一定的帮助,感兴趣的小伙伴跟着小编一起来看看吧
    2024-05-05
  • GO语言实现简单TCP服务的方法

    GO语言实现简单TCP服务的方法

    这篇文章主要介绍了GO语言实现简单TCP服务的方法,实例分析了Go语言实现TCP服务的技巧,需要的朋友可以参考下
    2015-03-03
  • Golang异常处理之优雅地控制和处理异常

    Golang异常处理之优雅地控制和处理异常

    在Golang中,异常处理是非常重要的一部分,能够有效地控制和处理代码中的异常情况。通过Golang的异常处理机制,可以优雅地捕获和处理异常,保障代码的可靠性和稳定性。同时,Golang还提供了丰富的工具和API,帮助开发者更加轻松地进行异常处理
    2023-04-04
  • Golang中Kafka的重复消费和消息丢失问题的解决方案

    Golang中Kafka的重复消费和消息丢失问题的解决方案

    在Kafka中无论是生产者发送消息到Kafka集群还是消费者从Kafka集群中拉取消息,都是容易出现问题的,比较典型的就是消费端的重复消费问题、生产端和消费端产生的消息丢失问题,下面将对这两个问题出现的场景以及常见的解决方案进行讲解
    2023-08-08
  • ubuntu下搭建Go语言(golang)环境

    ubuntu下搭建Go语言(golang)环境

    这篇文章主要介绍了ubuntu下搭建Go语言(golang)环境,需要的朋友可以参考下
    2015-01-01

最新评论