Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库,封装了常用的函数实现,本文介绍 golang 版本的 lodash 实现。
介绍
- samber/lo 是 Lodash 风格的 Go 库基于 Go 1.18+ 泛型(映射、过滤器、包含、查找…)
示例
package main
import (
"fmt"
"strconv"
"strings"
"github.com/samber/lo"
)
func main() {
// Filter 根据条件过滤数组
_filter := lo.Filter([]int{1, 2, 3, 4}, func(x int, index int) bool {
return x%2 == 0
})
// []int{2, 4}
fmt.Printf("%#v\n", _filter)
// Map 操作一种类型的切片并将其转换为另一种类型的切片
_map := lo.Map([]int64{1, 2, 3, 4}, func(x int64, index int) string {
return strconv.FormatInt(x, 10)
})
// []string{"1", "2", "3", "4"}
fmt.Printf("%#v\n", _map)
// FilterMap 返回使用给定回调函数过滤和映射后得到的切片
_filterMap := lo.FilterMap([]string{"cpu", "gpu", "mouse", "keyboard"}, func(x string, _ int) (string, bool) {
if strings.HasSuffix(x, "pu") {
return x, true
}
return "", false
})
// []string{"cpu", "gpu"}
fmt.Printf("%#v\n", _filterMap)
// FlatMap 处理一个切片,并将其转换和扁平化为另一种类型的切片。变换函数既可以返回一个切片,也可以返回一个 nil,在 nil 的情况下,最终的切片不会添加任何值
_flatMap := lo.FlatMap([]int64{0, 1, 2}, func(x int64, _ int) []string {
return []string{
strconv.FormatInt(x, 10),
strconv.FormatInt(x, 10),
}
})
// []string{"0", "0", "1", "1", "2", "2"}
fmt.Printf("%#v\n", _flatMap)
// Reduces 将集合减少为单个值
_reduces := lo.Reduce([]int{1, 2, 3, 4}, func(agg int, item int, _ int) int {
return agg + item
}, 0)
// 10
fmt.Printf("%#v\n", _reduces)
// ForEach 遍历集合中的元素,并在每个元素上调用函数
lo.ForEach([]string{"hello", "world"}, func(x string, _ int) {
println(x)
})
// prints "hello\nworld\n"
// ForEachWhile 遍历集合元素并对每个元素调用 iteratee 集合返回值,决定继续还是中断,类似于 do while()
lo.ForEachWhile([]int64{1, 2, -42, 4}, func(x int64, _ int) bool {
if x < 0 {
return false
}
fmt.Println(x)
return true
})
// 1
// 2
// 调用 n 次遍历器,返回一个包含每次调用结果的数组
_times := lo.Times(3, func(i int) string {
return strconv.FormatInt(int64(i), 10)
})
// []string{"0", "1", "2"}
fmt.Printf("%#v\n", _times)
// Uniq 返回数组的无重复版本,结果值的顺序由它们在数组中出现的顺序决定
_uniq := lo.Uniq([]int{1, 2, 2, 1})
// []int{1, 2}
fmt.Printf("%#v\n", _uniq)
// UniqBy 返回数组的无重复版本
_uniqBy := lo.UniqBy([]int{0, 1, 2, 3, 4, 5}, func(i int) int {
return i % 3
})
// []int{0, 1, 2}
fmt.Printf("%#v\n", _uniqBy)
// GroupBy 返回一个对象,该对象由通过 iteratee 运行集合中每个元素的结果生成的键组成
_groupBy := lo.GroupBy([]int{0, 1, 2, 3, 4, 5}, func(i int) int {
return i % 3
})
// map[int][]int{0: []int{0, 3}, 1: []int{1, 4}, 2: []int{2, 5}}
fmt.Printf("%#v\n", _groupBy)
// Chunk 返回一个元素数组,该数组的元素被分成长度为 size 的组
_chunk := lo.Chunk([]int{0, 1, 2, 3, 4, 5}, 2)
// [][]int{{0, 1}, {2, 3}, {4, 5}}
fmt.Printf("%#v\n", _chunk)
// Flatten 返回一个单层数组
_flatten := lo.Flatten([][]int{{0, 1}, {2, 3, 4, 5}})
// []int{0, 1, 2, 3, 4, 5}
fmt.Printf("%#v\n", _flatten)
// Shuffle 返回一个洗牌值数组。使用 Fisher-Yates 洗牌算法
_shuffle := lo.Shuffle([]int{0, 1, 2, 3, 4, 5})
// []int{1, 4, 0, 3, 5, 2}
fmt.Printf("%#v\n", _shuffle)
// Reverse 反转数组
_reverse := lo.Reverse([]int{0, 1, 2, 3, 4, 5})
// []int{5, 4, 3, 2, 1, 0}
fmt.Printf("%#v\n", _reverse)
// Drop 从片段或数组的开头删除 n 个元素
_drop := lo.Drop([]int{0, 1, 2, 3, 4, 5}, 2)
// []int{2, 3, 4, 5}
fmt.Printf("%#v\n", _drop)
// DropRight 从片段或数组末尾删除 n 个元素
_dropRight := lo.DropRight([]int{0, 1, 2, 3, 4, 5}, 2)
// []int{0, 1, 2, 3}
fmt.Printf("%#v\n", _dropRight)
// DropWhile 在函数返回 true 时,从片段或数组的开头删除元素
_dropWhile := lo.DropWhile([]string{"a", "aa", "aaa", "aa", "aa"}, func(val string) bool {
return len(val) <= 2
})
// []string{"aaa", "aa", "aa"}
fmt.Printf("%#v\n", _dropWhile)
// DropRightWhile 在函数返回 true 时,从片段或数组的末尾删除元素
_dropRightWhile := lo.DropRightWhile([]string{"a", "aa", "aaa", "aa", "aa"}, func(val string) bool {
return len(val) <= 2
})
// []string{"a", "aa", "aaa"}
fmt.Printf("%#v\n", _dropRightWhile)
// DropByIndex 按索引从片段或数组中删除元素,负索引将从片段末尾删除元素
_dropByIndex := lo.DropByIndex([]int{0, 1, 2, 3, 4, 5}, 2, 4, -1)
// []int{0, 1, 3}
fmt.Printf("%#v\n", _dropByIndex)
// Reject 与 Filter 相反,该方法返回函数不返回真值的集合元素
_reject := lo.Reject([]int{1, 2, 3, 4}, func(x int, _ int) bool {
return x%2 == 0
})
// []int{1, 3}
fmt.Printf("%#v\n", _reject)
// RejectMap
_rejectMap := lo.RejectMap([]int{1, 2, 3, 4}, func(x int, _ int) (int, bool) {
return x * 10, x%2 == 0
})
// []int{10, 30}
fmt.Printf("%#v\n", _rejectMap)
// FilterReject 混合 Filter 和 Reject,此方法返回两个切片,一个用于函数返回 true 的集合元素,另一个用于函数不返回 true 的元素
kept, rejected := lo.FilterReject([]int{1, 2, 3, 4}, func(x int, _ int) bool {
return x%2 == 0
})
// []int{2, 4}
// []int{1, 3}
fmt.Printf("%#v %#v\n", kept, rejected)
// Count 计算集合中比较等于 value 的元素数量
_count := lo.Count([]int{1, 5, 1}, 1)
// 2
fmt.Printf("%#v\n", _count)
// CountBy 计算集合中函数为真的元素个数
_countBy := lo.CountBy([]int{1, 5, 1}, func(i int) bool {
return i < 4
})
// 2
fmt.Printf("%#v\n", _countBy)
// CountValues
// CountValuesBy
// Subset 返回从偏移元素到 length 元素的切片副本。类似 slice[start:start+length],但溢出时不会 panic
_subset := lo.Subset([]int{0, 1, 2, 3, 4}, 2, 3)
// []int{2, 3, 4}
fmt.Printf("%#v\n", _subset)
// Slice 返回从开始到结束(不包括结束)的切片副本,类似 slice[start:end],但溢出时不会 panic
_slice := lo.Slice([]int{0, 1, 2, 3, 4}, 2, 3)
// []int{2}
fmt.Printf("%#v\n", _slice)
// Replace
// ReplaceAll
// Compact
// IsSorted 检查切片是否已排序
_isSorted := lo.IsSorted([]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
// true
fmt.Printf("%#v\n", _isSorted)
// IsSortedByKey 检查切片是否按 iteratee 排序
_isSortedByKey := lo.IsSortedByKey([]string{"a", "bb", "ccc"}, func(s string) int {
return len(s)
})
// true
fmt.Printf("%#v\n", _isSortedByKey)
// Splice
// Keys 创建map键的切片
_keys := lo.Keys(map[string]int{"foo": 1, "bar": 2})
// []string{"foo", "bar"}
fmt.Printf("%#v\n", _keys)
_keys = lo.Keys(map[string]int{"foo": 1, "bar": 2}, map[string]int{"baz": 3})
// []string{"foo", "bar", "baz"}
fmt.Printf("%#v\n", _keys)
// UniqKeys 创建一个包含唯一map键的数组
_uniqKeys := lo.UniqKeys(map[string]int{"foo": 1, "bar": 2}, map[string]int{"bar": 3})
// []string{"foo", "bar"}
fmt.Printf("%#v\n", _uniqKeys)
// HasKey 返回给定键是否存在
_hasKey := lo.HasKey(map[string]int{"foo": 1, "bar": 2}, "foo")
// true
fmt.Printf("%#v\n", _hasKey)
// Values 创建一个包含map数值的数组
_values := lo.Values(map[string]int{"foo": 1, "bar": 2}, map[string]int{"baz": 3})
// []int{1, 2, 3}
fmt.Printf("%#v\n", _values)
// UniqValues 创建一个包含唯一map值的数组
_uniqValues := lo.UniqValues(map[string]int{"foo": 1, "bar": 2}, map[string]int{"baz": 3})
// []int{1, 2, 3}
fmt.Printf("%#v\n", _uniqValues)
// ValueOr 返回给定键的值,如果键不存在,则返回默认值
_valueOr := lo.ValueOr(map[string]int{"foo": 1, "bar": 2}, "baz", 42)
// 42
fmt.Printf("%#v\n", _valueOr)
// PickBy
// PickByKeys
// PickByValues
// OmitBy 根据给定函数过滤后返回相同的map类型
_omitBy := lo.OmitBy(map[string]int{"foo": 1, "bar": 2, "baz": 3}, func(key string, value int) bool {
return value%2 == 1
})
// map[string]int{"bar": 2}
fmt.Printf("%#v\n", _omitBy)
// OmitByKeys 根据 key 忽略
// OmitByValues // 根据 value 忽略
// Entries
// FromEntries
// Invert key变value,value变key。可能因为重复的value而丢失数据
// Assign 从左到右,逐个合并map,返回新map
// MapKeys 操作map键并将其转换为另一种类型的映射
// MapValues 操作map值并将其转换为另一种类型的映射
// MapEntries
// MapToSlice
// Range / RangeFrom / RangeWithSteps 创建一个数组(正数和/或负数),从起始数到结束数,但不包括结束数
// Clamp
// Sum
_sum := lo.Sum([]int{1, 2, 3, 4, 5})
// 15
fmt.Printf("%#v\n", _sum)
// SumBy 使用迭代函数的给定返回值汇总集合中的值
_sumBy := lo.SumBy([]string{"foo", "bar"}, func(item string) int {
return len(item)
})
// 6
fmt.Printf("%#v\n", _sumBy)
// Mean
// MeanBy
// RandomString
// Substring
// ChunkString
// RuneLength utf8.RuneCountInString 的别名,用于返回字符串中的符文数量
_runeLength := lo.RuneLength("hello 世界")
// 5
fmt.Printf("%#v\n", _runeLength)
// PascalCase
fmt.Printf("%s\n", lo.PascalCase("hello_world")) // HelloWorld
// CamelCase
fmt.Printf("%s\n", lo.CamelCase("hello_world")) // helloWorld
// KebabCase
fmt.Printf("%s\n", lo.KebabCase("helloWorld")) // hello-world
// SnakeCase
fmt.Printf("%s\n", lo.SnakeCase("helloWorld")) // hello_world
// Words 分词
// Capitalize 首字母大写
// Ellipsis 省略字符 ...
// Duration 返回执行函数所花费的时间
// Duration0 -> Duration10 返回执行函数所用的时间,带返回值
// ChannelDispatcher
// SliceToChannel
// ChannelToSlice
// Generator
// Buffer
// BufferWithTimeout
// FanIn FanOut
// Contains 如果集合中存在元素,则返回 true
_contains := lo.Contains([]int{0, 1, 2, 3, 4, 5}, 5)
// true
fmt.Printf("%#v\n", _contains)
// ContainsBy 如果函数函数返回 true,则返回 true
_containsBy := lo.ContainsBy([]int{0, 1, 2, 3, 4, 5}, func(x int) bool {
return x == 3
})
// true
fmt.Printf("%#v\n", _containsBy)
// Every 如果子集的所有元素都包含在集合中或者子集为空,则返回 true
_every := lo.Every([]int{0, 1, 2, 3, 4, 5}, []int{0, 2})
// true
fmt.Printf("%#v\n", _every)
// EveryBy 如果函数对集合中的所有元素都返回 true,或者集合为空,则返回 true
_everyBy := lo.EveryBy([]int{1, 2, 3, 4}, func(x int) bool {
return x < 5
})
// true
fmt.Printf("%#v\n", _everyBy)
// Some 如果集合中至少包含子集的 1 个元素,则返回 true。如果子集为空 Some 返回 false
// SomeBy 如果函数对集合中的任何元素返回 true,则返回 true。如果集合为空 SomeBy 返回 false
// None 如果集合中不包含子集的元素或者子集为空,则返回 true
// NoneBy 如果函数对集合中没有任何元素返回 true 或集合为空,则返回 true
// Intersect 返回两个集合之间的交集
// Difference 返回两个集合之间的差异
// Union 返回的所有不同的元素,结果不会改变元素的顺序比较
_union := lo.Union([]int{0, 1, 2, 3, 4, 5}, []int{0, 2}, []int{0, 10})
// []int{0, 1, 2, 3, 4, 5, 10}
fmt.Printf("%#v\n", _union)
// Without 返回不包括所有给定值的切片
_without := lo.Without([]int{0, 2, 10}, 0, 1, 2, 3, 4, 5)
// []int{10}
fmt.Printf("%#v\n", _without)
// WithoutEmpty 返回不包括空值的切片
_withoutEmpty := lo.WithoutEmpty([]int{0, 2, 10}) // lo.Compact
// []int{2, 10}
fmt.Printf("%#v\n", _withoutEmpty)
// IndexOf 返回在数组中第一次出现某个值的索引,如果找不到该值则返回 -1
_indexOf := lo.IndexOf([]int{0, 1, 2, 1, 2, 3}, 2)
// 2
fmt.Printf("%#v\n", _indexOf)
// LastIndexOf 返回在数组中找到最后一次出现的值的索引,如果找不到该值则返回 -1
_lastIndexOf := lo.LastIndexOf([]int{0, 1, 2, 1, 2, 3}, 2)
// 4
fmt.Printf("%#v\n", _lastIndexOf)
// Find 基于函数搜索切片中的元素。如果找到元素,则返回元素并返回 true
str, ok := lo.Find([]string{"a", "b", "c", "d"}, func(i string) bool {
return i == "b"
})
// "b", true
fmt.Printf("%s %t\n", str, ok)
// FindIndexOf 根据函数搜索切片中的元素并返回索引和 true。如果未找到该元素,则返回 -1 和 false
str, index, ok := lo.FindIndexOf([]string{"a", "b", "a", "b"}, func(i string) bool {
return i == "b"
})
// "b", 1, true
fmt.Printf("%s %d %t\n", str, index, ok)
// FindLastIndexOf
// FindOrElse 根据函数在片段中搜索元素。如果找到则返回该元素,否则返回给定的后备值
// FindKey 返回第一个值匹配的键
_findKey, ok := lo.FindKey(map[string]int{"foo": 1, "bar": 2, "baz": 3}, 2)
// "bar", true
fmt.Printf("%s %t\n", _findKey, ok)
// FindKeyBy 返回第一个元素的键谓词返回 true
// FindUniques 返回一个包含集合中所有唯一元素的切片
// FindUniquesBy
// FindDuplicates 返回一个切片,其中包含集合中每个重复元素的第一次出现
// FindDuplicatesBy
// Min
// MinBy
// Earliest 搜索最近的时间
// EarliestBy
// Max 搜索集合的最大值
// MaxBy
// Latest
// LatestBy
// First
// FirstOrEmpty
// FirstOr
// Last 返回集合的最后一个元素,如果为空则返回错误
// LastOrEmpty
// LastOr
// Nth 返回序号的值
// Sample 从集合中返回一个随机项目
_sample := lo.Sample([]string{"a", "b", "c"})
// a random string from []string{"a", "b", "c"}
fmt.Printf("%#v\n", _sample)
// Ternary 1 行 if/else 语句
_ternary := lo.Ternary(true, "a", "b")
// "a"
fmt.Printf("%#v\n", _ternary)
// TernaryF 1 行 if/else 语句,其选项是函数。
_ternaryF := lo.TernaryF(true, func() string { return "a" }, func() string { return "b" })
// "a"
fmt.Printf("%#v\n", _ternaryF)
// If / ElseIf / Else
// Switch / Case / Default
// IsNil
// ToPtr
// Nil
// EmptyableToPtr
// FromPtr
// FromPtrOr
// ToSlicePtr
// FromSlicePtr
// FromSlicePtrOr
// ToAnySlice
// FromAnySlice
// Empty 返回一个空值
lo.Empty[int]()
// 0
lo.Empty[string]()
// ""
lo.Empty[bool]()
// false
// IsEmpty 如果参数为零值则返回 true
lo.IsEmpty(0)
// true
lo.IsEmpty(42)
// false
lo.IsEmpty("")
// true
lo.IsEmpty("foobar")
// false
// IsNotEmpty
lo.IsNotEmpty(0)
// false
lo.IsNotEmpty(42)
// true
lo.IsNotEmpty("")
// false
lo.IsNotEmpty("foobar")
// true
// Coalesce 返回第一个非空参数。参数必须具有可比性
result, ok := lo.Coalesce(0, 1, 2, 3)
// 1 true
fmt.Printf("%d %t\n", result, ok)
// CoalesceOrEmpty
// Partial
// Partial2 -> Partial5
// Attempt 调用函数 N 次,直到返回有效输出
iter, err := lo.Attempt(42, func(i int) error {
if i == 5 {
return nil
}
return fmt.Errorf("failed")
})
// 6 nil
fmt.Printf("%#v %v\n", iter, err)
// AttemptWithDelay
// AttemptWhile
// AttemptWhileWithDelay
// Debounce
// DebounceBy
// Async
// Async{0->6}
// Transaction
// WaitFor
// WaitForWithContext
// Validate
// Must 如果第二个参数为错误或 false,则将函数调用包装为恐慌,否则返回值
// Must{0->6} Must* 与 Must 具有相同的行为,但返回多个值
// func example0() (error)
// func example1() (int, error)
// func example2() (int, string, error)
// func example3() (int, string, time.Date, error)
// func example4() (int, string, time.Date, bool, error)
// func example5() (int, string, time.Date, bool, float64, error)
// func example6() (int, string, time.Date, bool, float64, byte, error)
// lo.Must0(example0())
// val1 := lo.Must1(example1()) // alias to Must
// val1, val2 := lo.Must2(example2())
// val1, val2, val3 := lo.Must3(example3())
// val1, val2, val3, val4 := lo.Must4(example4())
// val1, val2, val3, val4, val5 := lo.Must5(example5())
// val1, val2, val3, val4, val5, val6 := lo.Must6(example6())
// Try 调用该函数并在发生错误和恐慌时返回 false
// Try{0->6} 与 Try 行为相同,但回调返回 2 个变量
// TryOr
// TryOr{0->6}
// TryWithErrorValue
// TryCatch
// TryCatchWithErrorValue
// ok := lo.Try(func() error {
// panic("error")
// return nil
// })
// false
// ok := lo.Try(func() error {
// return nil
// })
// true
// ok := lo.Try(func() error {
// return fmt.Errorf("error")
// })
// false
// ErrorsAs
// err := doSomething()
// if rateLimitErr, ok := lo.ErrorsAs[*RateLimitError](err); ok {
// retry later
// }
}