lo

这是一个像是 js 中 lodash 的库, 因为先接触的语言中 js 有这种库的需求, 所以类比为 js 的 lodash.

也因为 go 在 1.18 中加入了泛型, 所以学习这种工具库可以更好的理解一个语言的对泛型的设计.

虽然 1.18 是前几年出的了, 但是学的时候仍旧是用旧的教程.

为什么有这种库

go 是一门比较精简的语言, 语言特性算是比较少的, 当然也是和 c# python kotlin 相比, 甚至是 cpp.

这大概是 go 的核心理念, 不希望一种逻辑有太多种类的写法, 不太好评价这种做法的好坏, 但是这导致了某些常用的逻辑总是需要很多行的实现.

这里实现一个三目运算

var result string
if condition {
    result = "value1"
} else {
    result = "value2"
}

虽然这样的代码比三目运算符长, 但它更明确,更容易阅读,这是 go 的设计哲学之一.

应该有不少人在使用 go 的时候, 像我一样并不是来通透 go 语言的, 只是想节约一些性能需要, 还想用一些比较成熟的库.

解决了什么

常用操作

有关数据结构的变换, 是可以减少代码篇幅的好文明。

让程序更好读。

例如,foreach、find、filter etc. 。

语言遗留问题

这里又要拿出 js 的 lodash 说事情了, js 的标准库实现的并不差, 但是 lodash 还是非常的实用。

当然这里有一些历史遗留问题, 这里举的例子可能比较古早。

标准数据类型

在 go 中,"空"这个概念是由 nil 完成的。

但是 int bool string 在任何情况下, 都是有默认值的。

package main
import "fmt"
func main(){
    var num int
    var flag bool
    var str string
    fmt.Println(num)    // 输出:0
    fmt.Println(flag)   // 输出:false
    fmt.Println(str)    // 输出:""
}

其他所有的数据类型都是可以被称为 nil 的空, 空切片、空映射、空通道、空指针、空接口。

number 和 bool 有默认值还是可以接受的, 至于 string 为什么有默认值, 是一个很奇怪的设定。

type person struct {
	Name string
}

func TestString(t *testing.T) {
	var s string
	t.Logf("\"%s\"", s) // ""

	t.Logf("\"%s\"", person{}.Name) // ""
}
  1. JavaScript 的遗留问题

在 JavaScript 中,你可能会碰到以下的问题:

  • 一个字符串可能是空的,但也可能是只包含空格的。
  • 一个数组可能长度为 0。
  • 一个对象可能没有任何属性。
  • null 和 undefined 也可以被视为“空”。

为了检查所有这些情况,你需要编写多条逻辑语句,这样就变得非常麻烦。

Lodash 提供了一个非常方便的 isEmpty 方法,它会为你处理所有这些情况:

_.isEmpty({});        // true
_.isEmpty([]);        // true
_.isEmpty('');        // true
_.isEmpty(' ');       // false
_.isEmpty(null);      // true
_.isEmpty(undefined); // true

这种问题即便在 es6 等后续完善之后, 对于一些常见的实用功能,如isEmpty、isNull、或更加复杂的数据处理和验证函数,ECMAScript官方还没有引入与Lodash或其他实用程序库相似的特性。

这种便捷的方式,在 go 的 lo 库被保留的下来。

lo.IsEmpty(0)           // true
lo.IsEmpty(42)          // false
lo.IsEmpty("")          // true
lo.IsEmpty("foobar")    // false

type test struct {
    foobar string
}

lo.IsEmpty(test{foobar: ""})        // true
lo.IsEmpty(test{foobar: "foobar"})  // false