Golang lodash 库使用

发布时间: 更新时间: 总字数:3369 阅读时间:7m 作者: IP上海 分享 网址

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
	// }
}

参考

  1. https://github.com/samber/lo
Home Archives Categories Tags Statistics
本文总阅读量 次 本站总访问量 次 本站总访客数