Skip to content

现代的Go工具库go-funk

1. 介绍

Go-funk 是基于反射(reflect)实现的一个现代Go工具库,封装了对slice/map/struct/string等的操作。

2. 下载

# 下载
go get github.com/thoas/go-funk
# 引入
import github.com/thoas/go-funk

3. 切片(slice)操作

3.1 判断元素是否存在

  • funk.Contains: 接收任意类型。
  • funk.ContainsX: X代表具体类型,如:ContainsInt、ContainsString...
func TestExist(t *testing.T) {
 // 判断任意类型
 fmt.Println("str->", funk.Contains([]string{"a", "b"}, "a"))
 // int 类型
 fmt.Println("int->", funk.ContainsInt([]int{1, 2}, 1))
}
/**输出
=== RUN   TestExist
str-> true
int-> true
--- PASS: TestExist (0.00s)
PASS
*/

3.2 查找元素第一次出现位置

  • funk.IndexOf: 接收任意类型,不存在则返回-1
  • funk.IndexOfX: X代表具体类型,不存在则返回-1
func TestIndexOf(t *testing.T) {
 strArr := []string{"go", "java", "c", "java"}
 // 具体类型
 fmt.Println("c: ", funk.IndexOfString(strArr, "c"))
 // 验证第一次出现位置
 fmt.Println("java: ", funk.IndexOfString(strArr, "java"))
 // 任意类型
 fmt.Println("go: ", funk.IndexOf(strArr, "go"))
 // 不存在时返回-1
 fmt.Println("php: ", funk.IndexOfString(strArr, "php"))
}
/**输出
=== RUN   TestIndexOf
c:  2
java:  1
go:  0
php:  -1
--- PASS: TestIndexOf (0.00s)
PASS
*/

3.3 查找元素最后一次出现位置

  • funk.LastIndexOf: 接收任意类型,不存在则返回-1
  • funk.LastIndexOfX: X代表具体类型,不存在则返回-1
// 查找元素最后一次出现的位置
func TestLastOf(t *testing.T) {
 strArr := []string{"go", "java", "c", "java"}
 // 具体类型
 fmt.Println("c: ", funk.LastIndexOfString(strArr, "c"))
 // 验证第一次出现位置
 fmt.Println("java: ", funk.LastIndexOfString(strArr, "java"))
 // 任意类型
 fmt.Println("go: ", funk.LastIndexOf(strArr, "go"))
 // 不存在时返回-1
 fmt.Println("php: ", funk.LastIndexOf(strArr, "php"))
}
/**输出
=== RUN   TestLastOf
c:  2
java:  3
go:  0
php:  -1
--- PASS: TestLastOf (0.00s)
PASS
*/

3.4 批量查找(都有则True)

go func Every(in interface{}, elements ...interface{}) bool

  • elements都在in中时,则返回true; 否则为false;
func TestEvery(t *testing.T) {
 strArr := []string{"go", "java", "c", "python"}
 fmt.Println("都存在:", funk.Every(strArr, "go", "c"))
 fmt.Println("有一个不存在:", funk.Every(strArr, "php", "go"))
 fmt.Println("都不存在:", funk.Every(strArr, "php", "c++"))
}
/**输出
=== RUN   TestEvery
都存在: true
有一个不存在: false
都不存在: false
--- PASS: TestEvery (0.00s)
PASS
*/

3.5 批量查找(有一则True)

go func Some(in interface{}, elements ...interface{}) bool

  • elements至少有一个在in中时,则返回true; 否则为false;
// 批量查找,有一则返回true
func TestSome(t *testing.T) {
 strArr := []string{"go", "java", "c", "python"}
 fmt.Println("都存在:", funk.Some(strArr, "go", "c"))
 fmt.Println("至少一个存在:", funk.Some(strArr, "php", "go"))
 fmt.Println("都不存在:", funk.Some(strArr, "php", "c++"))
}
/***输出
=== RUN   TestSome
都存在: true
至少一个存在: true
都不存在: false
--- PASS: TestSome (0.00s)
PASS
*/

3.6 获取最后或第一个元素

// 获取第一个元素 或 最后一个元素
func TestLastOrFirst(t *testing.T) {
 number := []int{10, 30, 12, 23}
 // 获取第一个元素
 fmt.Println("Head: ", funk.Head(number))
 // 获取最后一个元素
 fmt.Println("Last: ", funk.Last(number))
}
/**输出
=== RUN   TestLastOrFirst
Head:  10
Last:  23
--- PASS: TestLastOrFirst (0.00s)
PASS
*/

3.7 用元素填充切片

go func Fill(in interface{}, fillValue interface{}) (interface{}, error)

  • in中的所有元素,设置成fillValue
// 填充元素
func TestFill(t *testing.T) {
 // 初始化切片
 var data = make([]int, 3)
 fill, _ := funk.Fill(data, 100)
 fmt.Printf("fill: %v \n", fill)
 // 将所有值设置成2
 input := []int{1, 2, 3}
 result, _ := funk.Fill(input, 2)
 fmt.Printf("result: %v \n", result)
 var structData = make([]Student, 2)
 stuInfo, _ := funk.Fill(structData, Student{Name: "张三", Age: 18})
 fmt.Printf("stuInfo: %v \n", stuInfo)
}
/**输出
=== RUN   TestFill
fill: [100 100 100] 
result: [2 2 2] 
stuInfo: [{张三 18} {张三 18}] 
--- PASS: TestFill (0.00s)
PASS
*/

3.8 取两个切片共同元素结果集

  • Join(larr, rarr interface{}, fnc JoinFnc): 当fnc=funk.InnerJoin,代表合并两个任意类型切片。
  • JoinXXX(larr, rarr interface{}, fnc JoinFnc): 指定类型合并,推荐使用。
type cus struct {
 Name string
 Age  int
 Home string
}
func TestJoin(t *testing.T) {
 a := []int64{1, 3, 5, 7}
 b := []int64{3, 7}
 // 任意类型切片交集
 join := funk.Join(a, b, funk.InnerJoin)
 fmt.Println("join = ", join)
 // 指定类型取交集
 joinInt64 := funk.JoinInt64(a, b, funk.InnerJoinInt64)
 fmt.Println("joinInt64 = ", joinInt64)
 // 自定义结构体交集
 sliceA := []cus{
  {"张三", 20, "北京"},
  {"李四", 22, "南京"},
 }
 sliceB := []cus{
  {"张三", 20, "北京"},
  {"李四", 22, "上海"},
 }
 res := funk.Join(sliceA, sliceB, funk.InnerJoin)
 fmt.Println("自定义结构体: ", res)
}
/**输出
=== RUN   TestJoin
join =  [3 7]
joinInt64 =  [3 7]
自定义结构体:  [{张三 20 北京}]
--- PASS: TestJoin (0.00s)
PASS
*/

3.9 获取去掉两切片共同元素结果集

同样使用JoinJoinXXX方法,而fnc设置成funk.OuterJoin

// 取差集
func TestDiffSlice(t *testing.T) {
 a := []int64{1, 3, 5, 7}
 b := []int64{3, 7, 10}
 // 任意类型切片交集
 join := funk.Join(a, b, funk.OuterJoin)
 fmt.Println("OuterJoin = ", join)
 // 指定类型取交集
 joinInt64 := funk.JoinInt64(a, b, funk.OuterJoinInt64)
 fmt.Println("joinInt64 = ", joinInt64)
 // 自定义结构体交集
 sliceA := []cus{
  {"张三", 20, "北京"},
  {"李四", 22, "南京"},
 }
 sliceB := []cus{
  {"张三", 20, "北京"},
  {"李四", 22, "上海"},
 }
 res := funk.Join(sliceA, sliceB, funk.OuterJoin)
 fmt.Println("自定义结构体: ", res)
}
/**输出
=== RUN   TestDiffSlice
OuterJoin =  [1 5 10]
joinInt64 =  [1 5 10]
自定义结构体:  [{李四 22 南京} {李四 22 上海}]
--- PASS: TestDiffSlice (0.00s)
PASS
*/

3.10 求只存在某切片的元素(除去共同元素)

func TestLeftAndRightJoin(t *testing.T) {
 a := []int64{10, 20, 30}
 b := []int64{30, 40}
 // 取出只在a,不在b的元素
 leftJoin := funk.Join(a, b, funk.LeftJoin)
 fmt.Println("只在a切片的元素: ", leftJoin)
 // 取出只在b,不在a的元素
 rightJoin := funk.Join(a, b, funk.RightJoin)
 fmt.Println("只在b切片的元素: ", rightJoin)
}
/**输出
=== RUN   TestLeftAndRightJoin
只在a切片的元素:  [10 20]
只在b切片的元素:  [40]
--- PASS: TestLeftAndRightJoin (0.00s)
PASS
*/

3.11 分别去掉两个切片共同元素(两结果集)

func TestDifferent(t *testing.T) {
 // 处理任意类型
 one := []interface{}{1, "go", 3.2, []int8{10}}
 two := []interface{}{2, "go", 3.2, []int{20}}
 oneRes, twoRes := funk.Difference(one, two)
 fmt.Println("oneRes: ", oneRes)
 fmt.Println("twoRes:  ", twoRes)

 // 只处理具体类型
 str1 := []string{"go", "php", "java"}
 str2 := []string{"c", "python", "java"}
 res, res1 := funk.DifferenceString(str1, str2)
 fmt.Println("res: ", res)
 fmt.Println("res1: ", res1)
}
/**输出
=== RUN   TestDifferent
oneRes:  [1 [10]]
twoRes:   [2 [20]]
res:  [go php]
res1:  [c python]
--- PASS: TestDifferent (0.00s)
PASS
*/

3.12 遍历切片

  • ForEach: 从左边遍历切片。
  • ForEachRight: 从右边遍历切片。
// 遍历切片
func TestForeachSlice(t *testing.T) {
 // 从左边遍历
 var leftRes []int
 funk.ForEach([]int{1, 2, 3, 4}, func(x int) {
  leftRes = append(leftRes, x*2)
 })
 fmt.Println("ForEach:", leftRes)
 // 从右边遍历
 var rightRes []int
 funk.ForEachRight([]int{1, 2, 3, 4}, func(x int) {
  rightRes = append(rightRes, x*2)
 })
 fmt.Println("ForEachRight:", rightRes)
}
/**输出
=== RUN   TestForeachSlice
ForEach: [2 4 6 8]
ForEachRight: [8 6 4 2]
--- PASS: TestForeachSlice (0.00s)
PASS
*/

3.13 删除首或尾

// 除去第一个 或者 最后一个
func TestDelLastOrFirst(t *testing.T) {
 a := []int{1, 2, 3, 4, 5, 6, 7}
 // 除去第一个,返回剩余元素
 fmt.Println(funk.Tail(a))
 // 除去最后一个,返回剩余元素
 fmt.Println(funk.Initial(a))
}
/**输出
=== RUN   TestDelLastOrFirst
[2 3 4 5 6 7]
[1 2 3 4 5 6]
--- PASS: TestDelLastOrFirst (0.00s)
PASS
*/

3.14 判断A切片是否属于B切片子集

Subset(x interface{}, y interface{}) bool: 判断x是否属于y的切片。

// 判断是否属于子集
func TestSubset(t *testing.T) {
 // 判断基础切片
 fmt.Println("是否属于子集:", funk.Subset([]int{1}, []int{1, 2}))
 // 判断自定义结构体切片
 subStu1 := []Student{{Name: "张三", Age: 18}}
 subStu2 := []Student{{Name: "张三", Age: 22}}
 allStu := []Student{
  {Name: "张三", Age: 18},
  {Name: "李四", Age: 22},
 }
 fmt.Println("subStu1: ", funk.Subset(subStu1, allStu))
 fmt.Println("subStu2: ", funk.Subset(subStu2, allStu))
 // 判断空切片是否属于另一切片子集
 fmt.Println("判断空集:", funk.Subset([]int{}, []int{1, 2}))
}
/**输出
=== RUN   TestSubset
是否属于子集: true
subStu1:  true
subStu2:  false
判断空集:true
--- PASS: TestSubset (0.00s)
PASS
*/

3.15 分组

Chunk(arr interface{}, size int) interface{}: 把arr按照每组size个进行分组

// 分组
func TestChunk(t *testing.T) {
 a := []int{1, 2, 3, 4, 5, 6, 7}
 // 分组(每组2个)
 fmt.Println(funk.Chunk(a, 2))
 // 分组自定义结构体切片 (每组2个)
 stuList := []Student{
  {Name: "张三", Age: 18},
  {Name: "小明", Age: 20},
  {Name: "李四", Age: 22},
  {Name: "赵武", Age: 32},
  {Name: "小英", Age: 19},
 }
 fmt.Println(funk.Chunk(stuList, 2))
}
/**输出
=== RUN   TestChunk
[[1 2] [3 4] [5 6] [7]]
[[{张三 18} {小明 20}] [{李四 22} {赵武 32}] [{小英 19}]]
--- PASS: TestChunk (0.00s)
PASS
*/

3.16 把结构体切片转成map

ToMap(in interface{}, pivot string) interface{}: 把切片in,转成以pivotkeymap

// 结构体转成Map
func TestToMap(t *testing.T) {
 bookList := []Book{
  {Id: 1, Name: "西游记"},
  {Id: 2, Name: "水浒传"},
  {Id: 3, Name: "三国演义"},
 }
 // 转成以Id为Key的Map
 fmt.Println("结果:", funk.ToMap(bookList, "Id"))
}
/**输出
=== RUN   TestToMap
结果: map[1:{1 西游记} 2:{2 水浒传} 3:{3 三国演义}]
--- PASS: TestToMap (0.00s)
PASS
*/

3.17 把切片值转成Map中的Key

func TestMap(t *testing.T) {
 // 将切片最为map的key
 r := funk.Map([]int{1, 2, 3, 4}, func(x int) (int, string) {
  return x, "go"
 })
 fmt.Println("r=", r)
}
/**输出
=== RUN   TestMap
r= map[1:go 2:go 3:go 4:go]
--- PASS: TestMap (0.00s)
PASS
*/

3.18 把二维切片转成一维切片

// 把二维切片转成一维切片
func TestFlatMap(t *testing.T) {
   r := funk.FlatMap([][]int{{1}, {2}, {3}, {4}}, func(x []int) []int {
      return x
   })
   fmt.Printf("%#v\n", r)
}
/**输出
=== RUN   TestFlatMap
[]int{1, 2, 3, 4}
--- PASS: TestFlatMap (0.00s)
PASS
*/

3.19 打乱切片

func TestShuffle(t *testing.T) {
 a := []int{0, 1, 2, 3, 4, 5, 6, 7}
 // 打乱多次
 for i := 1; i <= 3; i++ {
  fmt.Println(fmt.Sprintf("第%v次打乱a", i), funk.Shuffle(a))
 }
}
/**输出
=== RUN   TestShuffle
第1次打乱a [5 4 2 6 7 0 3 1]
第2次打乱a [1 6 7 3 2 5 0 4]
第3次打乱a [5 1 7 6 0 4 2 3]
--- PASS: TestShuffle (0.00s)
PASS
*/

3.20 反转切片

// 反转切片
func TestReverse(t *testing.T) {
 fmt.Println("ReverseInt:", funk.ReverseInt([]int{1, 2, 3, 4, 5, 6}))
 fmt.Println("Reverse,任意类型:", funk.Reverse([]interface{}{1, "2", 3.02, 4, "5", 6}))
 fmt.Println("Reverse,Str:", funk.ReverseStrings([]string{"a", "b", "c", "d"}))
}
/**输出
=== RUN   TestReverse
ReverseInt: [6 5 4 3 2 1]
Reverse,任意类型: [6 5 4 3.02 2 1]
Reverse,Str: [d c b a]
--- PASS: TestReverse (0.00s)
PASS
*/

3.21 元素去重

// 去重
func TestUniq(t *testing.T) {
 a := []int64{1, 2, 3, 4, 3, 2, 1}
 // 过滤整型类型
 fmt.Println("Uniq:", funk.Uniq(a))
 fmt.Println("UniqInt64:", funk.UniqInt64(a))
 b := []string{"php", "go", "c", "go"}
 // 过滤字符串类型
 fmt.Println("UniqString:", funk.UniqString(b))
}
/**输出
=== RUN   TestUniq
Uniq: [1 2 3 4]
UniqInt64: [1 2 3 4]
UniqString: [php go c]
--- PASS: TestUniq (0.00s)
PASS
*/

3.22 删除制定元素

// 删除制定元素
func TestWithOut(t *testing.T) {
 // 删除具体元素
 b := []int{10, 20, 30, 40}
 without := funk.Without(b, 30)
 fmt.Println("删除30:", without)
 // 删除自定义结构体元素
 stuList := []Student{
  {Name: "张三", Age: 18},
  {Name: "李四", Age: 22},
  {Name: "范五", Age: 24},
 }
 res := funk.Without(stuList, Student{Name: "李四", Age: 22})
 fmt.Println("删除李四:", res)
}
/**输出
=== RUN   TestWithOut
删除30: [10 20 40]
删除李四: [{张三 18} {范五 24}]
--- PASS: TestWithOut (0.00s)
PASS
*/

4. 映射(map)操作

4.1 获取所有的Key

// 获取map中所有的key
func TestMapKeys(t *testing.T) {
 res := map[string]int{
  "张三": 18,
  "李四": 20,
  "赵武": 25,
 }
 keys := funk.Keys(res)
 fmt.Printf("keys: %#v %T \n", keys, keys)
}
/**输出
=== RUN   TestMapKeys
keys: []string{"张三", "李四", "赵武"} []string 
--- PASS: TestMapKeys (0.00s)
PASS
*/

4.2 获取所有的Value

// 获取map中的所有values
func TestMapValues(t *testing.T) {
 res := map[string]int{
  "张三": 18,
  "李四": 20,
  "赵武": 25,
 }
 values := funk.Values(res)
 fmt.Printf("values: %#v %T \n", values, values)
}
/**输出
=== RUN   TestMapValues
values: []int{18, 20, 25} []int 
--- PASS: TestMapValues (0.00s)
PASS
*/

5. 结构体(struct)切片操作

5.1 取结构体某元素为切片

func TestGetToSlice(t *testing.T) {
 userList := []User{
  {
   Name: "张三",
   Home: struct {
    City string
   }{"北京"},
  },
  {
   Name: "小明",
   Home: struct {
    City string
   }{"南京"},
  },
 }
 // 取一层
 names := funk.Get(userList, "Name")
 fmt.Println("names:", names)
 // 取其他层
 homes := funk.Get(userList, "Home.City")
 fmt.Println("homes:", homes)
}
/**输出
=== RUN   TestGetToSlice
names: [张三 小明]
homes: [北京 南京]
--- PASS: TestGetToSlice (0.00s)
PASS
*/

6. 判断操作

6.1 判断相等

type Student struct {
 Name string
 Age  int
}
// 比较
func TestIsEqual(t *testing.T) {
 // 对比字符串
 fmt.Println("对比字符串:", funk.IsEqual("a", "a"))
 // 对比int
 fmt.Println("对比int:", funk.IsEqual(1, 1))
 // 对比float64
 fmt.Println("对比float64:", funk.IsEqual(float64(1), float64(1)))
 // 对比结构体
 stu1 := Student{Name: "张三", Age: 18}
 stu2 := Student{Name: "张三", Age: 18}
 fmt.Println("对比结构体:", funk.IsEqual(stu1, stu2))
}
/**输出
=== RUN   TestIsEqual
对比字符串: true
对比int: true
对比float64: true
对比结构体: true
--- PASS: TestIsEqual (0.00s)
PASS
*/

6.2 判断类型一致

// 判断类型是否一样
func TestIsType(t *testing.T) {
 var a, b int8 = 1, 2
 fmt.Println("A: ", funk.IsType(a, b))
 c := 3
 d := "3"
 fmt.Println("B:", funk.IsType(c, d))
}
/**输出
=== RUN   TestIsType
A:  true
B: false
--- PASS: TestIsType (0.00s)
PASS
*/

6.3 判断array|slice

// 判断是否是array|slice
func TestCollect(t *testing.T) {
 // slice
 a := []int{1, 2, 3}
 // 字符串
 b := "str"
 // 自定义结构体切片
 c := []Student{
  {Name: "张三", Age: 18},
  {Name: "李四", Age: 18},
 }
 // 数组类型
 d := [2]string{"c", "go"}
 fmt.Println("a:", funk.IsCollection(a))
 fmt.Println("b:", funk.IsCollection(b))
 fmt.Println("c:", funk.IsCollection(c))
 fmt.Println("d:", funk.IsCollection(d))
}
/**输出
=== RUN   TestCollect
a: true
b: false
c: true
d: true
--- PASS: TestCollect (0.00s)
PASS
*/

6.4 判断空

  • funk.IsEmpty(obj interface{}): 判断为空。
  • funk.NotEmpty(obj interface{}): 判断不为空。
// 判断是否为空
func TestIsEmpty(t *testing.T) {
 // 空结构体
 fmt.Println("空结构体", funk.IsEmpty([]int{}))
 // 空字符串
 fmt.Println("空字符串:", funk.IsEmpty(""))
 // 判断数字0
 fmt.Println("0:", funk.IsEmpty(0))
 // 判断字符串'0'
 fmt.Println("'0':", funk.IsEmpty("0"))
 // nil
 fmt.Println("nil:", funk.IsEmpty(nil))
}
/**输出
=== RUN   TestIsEmpty
空结构体 true
空字符串: true
0: true
'0': false
nil: true
--- PASS: TestEmpty (0.00s)
PASS
*/

7. 类型转换

7.1 任意数字转float64

go func ToFloat64(x interface{}) (float64, bool)

  • 将任何数字类型,转成float64类型, @注:只能是数字类型: uint8、uint16、uint32、uint64、int、int8、int16、int32、int64、float32、float64
// 数字型转浮点型
func TestToFloat64(t *testing.T) {
 // int to float64
 d1, _ := funk.ToFloat64(10)
 fmt.Printf("d1 = %v %T \n", d1, d1)
 //@会失败
 d2, err := funk.ToFloat64("10")
 fmt.Printf("d2 = %v %v \n", d2, err)
}
/**输出
=== RUN   TestToFloat64
d1 = 10 float64 
d2 = 0 false 
--- PASS: TestToFloat64 (0.00s)
PASS
*/

7.2 将X转成[]X

// 返回任一类型的类型切片
func TestSliceOf(t *testing.T) {
 a := []int{10, 20, 30}
 // []int 转成 [][]int
 fmt.Printf("%v %T \n", funk.SliceOf(a), funk.SliceOf(a))
 // string 转成 []string
 fmt.Printf("%v %T \n", funk.SliceOf("go"), funk.SliceOf("go"))
}
/**输出
=== RUN   TestSliceOf
[[10 20 30]] [][]int 
[go] []string 
--- PASS: TestSliceOf (0.00s)
PASS
*/

8.字符串操作

8.1 根据字符串生成切片

go func Shard(str string, width int, depth int, restOnly bool) []string

  • width: 代表根据几个字节生成一个元素。
  • depth: 将字符串前x个元素转成切片。
  • restOnly: 当为false时,最后一个元素为原字符串,当为true时,最后一个元素为原字符串剩余元素
// 将自定长度字符串生成切片
func TestShard(t *testing.T) {
 tokey := "Hello,Word"
 shard := funk.Shard(tokey, 1, 5, false)
 shard1 := funk.Shard(tokey, 1, 5, true)
 fmt.Println("shard: ", shard)
 fmt.Println("shard1: ", shard1)
 shard2 := funk.Shard(tokey, 2, 5, false)
 shard22 := funk.Shard(tokey, 2, 5, true)
 fmt.Println("shard2: ", shard2)
 fmt.Println("shard22: ", shard22)
}
/**
=== RUN   TestShard
shard:  [H e l l o Hello,Word]
shard1:  [H e l l o ,Word]
shard2:  [He ll o, Wo rd Hello,Word]
shard22:  [He ll o, Wo rd ]
--- PASS: TestShard (0.00s)
PASS
*/

9.数字计算

9.1 最大值(Max)

func TestMax(t *testing.T) {
 // 求最大int
 fmt.Println("MaxInt:", funk.MaxInt([]int{30, 10, 8, 11}))
 // 求最大浮点数
 fmt.Println("MaxFloat64:", funk.MaxFloat64([]float64{10.2, 11.0, 8.03}))
 // 求最大字符串
 fmt.Println("MaxString:", funk.MaxString([]string{"a", "d", "c", "b"}))
}
/**输出
=== RUN   TestMaxInt
MaxInt: 30
MaxFloat64: 11
MaxString: d
--- PASS: TestMaxInt (0.00s)
PASS
*/

9.2 最小值(Min)

func TestMin(t *testing.T) {
 // 求最小int
 fmt.Println("MinInt:", funk.MinInt([]int{30, 10, 8, 11}))
 // 求最小浮点数
 fmt.Println("MinFloat64:", funk.MinFloat64([]float64{10.2, 11.0, 8.03}))
 // 求最小字符串
 fmt.Println("MinString:", funk.MinString([]string{"a", "d", "c", "b"}))
}
/**输出
=== RUN   TestMin
MinInt: 8
MinFloat64: 8.03
MinString: a
--- PASS: TestMin (0.00s)
PASS
*/

9.3 求和(Sum)

// 求和
func TestSum(t *testing.T) {
 // 整型
 a := []int{5, 10, 15, 20}
 fmt.Println("int sum:", funk.Sum(a))
 // 浮点型
 b := []float64{5.11, 2.23, 3.31, 0.32}
 fmt.Println("float64 sum:", funk.Sum(b))
}
/**输出
=== RUN   TestSum
int sum: 50
float64 sum: 10.97
--- PASS: TestSum (0.00s)
PASS
*/

9.4 求乘积(Product)

// 求乘积
func TestProduct(t *testing.T) {
 // 整型
 a := []int{2, 3, 4, 5}
 fmt.Println("int Product:", funk.Product(a))
 // 浮点型
 b := []float64{1.1, 1.2, 1.3, 1.4}
 fmt.Println("float64 Product:", funk.Product(b))
}
/**输出
=== RUN   TestProduct
int Product: 120
float64 Product: 2.4024
--- PASS: TestProduct (0.00s)
PASS
*/

10. 其他操作

10.1 生成随机数

// 生成随机数
func TestRandom(t *testing.T) {
 for i := 1; i <= 3; i++ {
  // 生成任意数字类型
  fmt.Println(funk.RandomInt(1, 100))
 }
}
/**输出
=== RUN   TestRandom
24
79
21
--- PASS: TestRandom (0.00s)
PASS
*/

10.2 生成随机字符串

// 生成随机字符串
func TestRandomString(t *testing.T) {
 for i := 1; i <= 3; i++ {
  // 从默认字符串生成
  fmt.Println("从默认字符串生成:", funk.RandomString(i))
  // 从指的字符串生成
  fmt.Println("从指定字符串生成:", funk.RandomString(i, []rune{'您', '好', '北', '京'}))
 }
}
/**输出
=== RUN   TestRandomString
从默认字符串生成: B
从指定字符串生成: 京
从默认字符串生成: Ln
从指定字符串生成: 好北
从默认字符串生成: Dsc
从指定字符串生成: 您北京
--- PASS: TestRandomString (0.00s)
PASS
*/

10.3 三元运算

// 三元运算
func TestShortIf(t *testing.T) {
 fmt.Println("10 > 5 :", funk.ShortIf(10 > 5, 10, 5))
 fmt.Println("10.0 == 10 : ", funk.ShortIf(10.0 == 10, "yes", "no"))
 fmt.Println("'a' == 'b' : ", funk.ShortIf('a' == 'b', "equal chars", "unequal chars"))
}
/**输出
=== RUN   TestShortIf
10 > 5 : 10
10.0 == 10 :  yes
'a' == 'b' :  unequal chars
--- PASS: TestShortIf (0.00s)
PASS
*/