阅读量:2
背景:
由于团队不是专业级别的go开发人员,主开发还是java,用惯了java的lambda表达式特别是流式操作, 所以在用go语言时,发现切片处理起来比较麻烦,看看能不能支持类似流式操作,我这边就研究了下这块业务,发现是可以实现的,同时要支持所有类型,所以必然要支持泛型才可以,背景介绍完,开始正题:
定义泛型的类型形参列表:
// SliceAble // // @Description: 泛型,如果需要支持其他类型,请自行添加 // @Author zhaosy // @date 2024-07-12 17:07:22 type SliceAble interface { Person | string | int }
定义切片类型
// Slice // 定义新切片类型 type Slice[T SliceAble] []T // NewSlice [T SliceAble] // // @Author zhaosy // @Description: newSlice // @date 2024-07-13 13:22:23 func NewSlice[T SliceAble](arr []T) Slice[T] { //这里为了不影响原始切片数据,所以进行copy,如果不关心可以删除直接返回arr即可 copyArr := make([]T, len(arr), len(arr)) copy(copyArr, arr) return copyArr } // Filter // // @Author zhaosy // @Description: 过滤,demo: // people := []lang.Person{ // {"Alice", 45}, // {"Elizabeth", 75}, // {"Alice", 25}, // {"Bob", 30}, // {"Alice", 2}, // {"Bob", 4}, // {"Colin", 5}, // {"Elizabeth", 34}, // } // // p := lang.NewSlice(people).Filter(func(i lang.Person) bool { // return i.Age > 30 // }) // // fmt.Println(p) //[{Alice 45} {Elizabeth 75} {Elizabeth 34}] // @date 2024-07-13 11:48:46 func (s Slice[T]) Filter(f func(T) bool) Slice[T] { var temp Slice[T] for _, v := range s { b := f(v) if b { temp = append(temp, v) } } return temp } // Sort // // @Author zhaosy // @Description: 排序: // 排序规则根据函数放回的bool类型进行排序,demo: // people := []lang.Person{ // {"Alice", 45}, // {"Elizabeth", 75}, // {"Alice", 25}, // {"Bob", 30}, // {"Alice", 2}, // {"Bob", 4}, // {"Colin", 5}, // {"Elizabeth", 34}, // } // lang.NewSlice(people).Sort(func(s lang.Slice[lang.Person], i, j int) bool { // return s[i].Age > s[j].Age // }) // fmt.Println(people) //结果:[{Elizabeth 75} {Alice 45} {Elizabeth 34} {Bob 30} {Alice 25} {Colin 5} {Bob 4} {Alice 2}] // // @date 2024-07-13 11:41:14 func (s Slice[T]) Sort(f func(s Slice[T], i, j int) bool) Slice[T] { sort.SliceStable(s, func(i, j int) bool { return f(s, i, j) }) return s } // Append // // @Author zhaosy // @Description: 追加元素;采用go 底层切片append方式 // @date 2024-07-13 13:13:09 func (s Slice[T]) Append(newObj T) Slice[T] { s = append(s, newObj) return s } // OnePointerObj // // @Author zhaosy // @Description: 返回单条数据实例,是指针类型,且判断是否为空 // @date 2024-07-13 13:13:41 func (s Slice[T]) OnePointerObj() *T { if len(s) == 0 { return nil } return &s[0] } // OnePointerObj // // @Author zhaosy // @Description: 返回json字符串,如果为空,直接返回空字符串 // @date 2024-07-13 13:47:41 func (s Slice[T]) ToJsonStr() string { b, err := json.Marshal(s) if err != nil { fmt.Println(err) return "" } return string(b) }
测试:
import ( "fmt" "testing" ) type Person struct { Name string `json:"name"` Age int `json:"age"` } func TestSlice_All(t *testing.T) { people := []Person{ {"张三", 45}, {"李四", 2}, {"王五", 25}, {"小明", 15}, {"小红", 2}, {"小蓝", 7}, {"小白", 5}, {"小花", 34}, } fmt.Println("原始数据:", people) //需求:根据年龄进行升序排序 p := NewSlice(people).Sort(func(s Slice[Person], i, j int) bool { return s[i].Age < s[j].Age }) fmt.Println("排序后:", p) //结果:[{李四 2} {小红 2} {小白 5} {小蓝 7} {小明 15} {王五 25} {小花 34} {张三 45}] //需求:过滤掉小于18岁的信息 p = NewSlice(people).Filter(func(pe Person) bool { return pe.Age > 18 }) fmt.Println("过滤18岁以后的:", p) //结果:[{张三 45} {王五 25} {小花 34}] //需求:向切片最后一个追加一个元素 p = NewSlice(people).Append(Person{ Name: "李玲", Age: 23, }) fmt.Println("追加元素后:", p) //结果:[{张三 45} {李四 2} {王五 25} {小明 15} {小红 2} {小蓝 7} {小白 5} {小花 34} {李玲 23}] //需求:获取切片第一个(这块目的是经过其他方法处理过后,直接获取第一个,比较简单直接) one := NewSlice(people).OnePointerObj() fmt.Println("第一个元素:", *one) //结果:{张三 45} //来一个比较常用的链式需求,需求:新增一个元素,并输出大于18岁且按照年龄进行升序排序的列表,最后以json方式输出 jsonStr := NewSlice(people).Append(Person{"李华", 35}).Sort(func(s Slice[Person], i, j int) bool { return s[i].Age < s[j].Age }).Filter(func(pe Person) bool { return pe.Age > 18 }).ToJsonStr() fmt.Println("结果:", jsonStr) //结果:[{"name":"王五","age":25},{"name":"小花","age":34},{"name":"李华","age":35},{"name":"张三","age":45}] //后期有其他需求可以继续添加,这样就比较简单了 }