文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Go语言中的Slice链式操作方法是什么

2023-07-05 23:41

关注

今天小编给大家分享一下Go语言中的Slice链式操作方法是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

示例

首先模拟一个业务场景,有订单、产品、自定义订单三个结构体,订单中包含多个产品:

type Order struct {Id       stringProducts []Product}type Product struct {Id    stringPrice int}type CustomOrder struct {Id string}

初始化模拟数据:

var orders = []Order{{Id: "o1",Products: []Product{{Id:    "p1",Price: 1,},{Id:    "p2",Price: 2,},},},{Id: "o2",Products: []Product{{Id:    "p3",Price: 3,},{Id:    "p4",Price: 4,},},},}

接下来对订单列表做各种操作:

// 过滤Id为o2的订单func TestFilter(t *testing.T) {res := Lists[Order](orders).Filter(func(o any) bool {return o.(Order).Id == "o2"}).Collect()t.Log(res) // [{o2 [{p3 3} {p4 4}]}]}// 将订单列表映射为自定义订单列表func TestMap(t *testing.T) {res := Lists[CustomOrder](orders).Map(func(o any) any {return CustomOrder{Id: "custom-" + o.(Order).Id,}}).Collect()t.Log(res) // [{custom-o1} {custom-o2}]}// 将每个订单里的产品展开,并映射为自定义订单func TestFlatAndMap(t *testing.T) {res := Lists[CustomOrder](orders).Flat(func(o any) []any {return Lists[any](o.(Order).Products).ToList()}).Map(func(p any) any {return CustomOrder{Id: "ProductId-" + p.(Product).Id,}}).Collect()t.Log(res) // [{ProductId-p1} {ProductId-p2} {ProductId-p3} {ProductId-p4}]}// 找到所有订单产品中价格最贵的那个产品func TestMax(t *testing.T) {res, found := Lists[Product](orders).Flat(func(o any) []any {return Lists[any](o.(Order).Products).ToList()}).Max(func(i, j any) bool {return i.(Product).Price > j.(Product).Price})t.Log(found, res) // true {p4 4}}

原理

type List[T any] struct {list []any}

将 go 中的原生切片包装成 List[T] 结构体,特别说明其中的泛型 T 是最终结果的元素类型,并不是原始传入切片的类型。

这样设计是因为 go 只能在构造结构体时指定泛型,因此将 List[T] 的泛型指定为最终结果的元素类型,就可以在操作完成后调用 Collect() 方法,得到最终的 T 类型切片,方便后面的业务逻辑使用。

因为 go 不支持在接受者函数中定义泛型,因此所有操作函数的参数和返回值类型只能定义为any,然后在函数体内转换为业务结构体使用,例如上面的 i.(Product).Price

此后将每一种操作,例如Filter、Map、Flat等,都返回List[T] 结构体,就可以实现链式操作。

实现

type List[T any] struct {list []any}func Lists[T any](items any) *List[T] {rv := reflect.ValueOf(items)if rv.Kind() != reflect.Slice {panic(fmt.Sprintf("not supported type: %v, please use slice instead", rv.Kind()))}l := rv.Len()s := make([]any, 0, l)for i := 0; i < l; i++ {s = append(s, rv.Index(i).Interface())}return &List[T]{list: s,}}func (s *List[T]) Filter(fn func(any) bool) *List[T] {l := make([]any, 0)for _, e := range s.list {if fn(e) {l = append(l, e)}}s.list = lreturn s}func (s *List[T]) Map(fn func(any) any) *List[T] {l := make([]any, 0)for _, element := range s.list {l = append(l, fn(element))}return &List[T]{list: l,}}func (s *List[T]) Flat(fn func(any) []any) *List[T] {l := make([]any, 0)for _, element := range s.list {l = append(l, fn(element)...)}return &List[T]{list: l,}}func (s *List[T]) Sort(fn func(i, j any) bool) *List[T] {if len(s.list) <= 0 {return s}sort.SliceStable(s.list, func(i, j int) bool {return fn(s.list[i], s.list[j])})return s}func (s *List[T]) Max(fn func(i, j any) bool) (T, bool) {return s.Sort(fn).FindFirst()}func (s *List[T]) FindFirst() (T, bool) {if len(s.list) <= 0 {var nonsense Treturn nonsense, false}return s.list[0].(T), true}func (s *List[T]) ToList() []any {return s.list}func (s *List[T]) Collect() []T {t := make([]T, 0)for _, a := range s.list {t = append(t, a.(T))}return t}

以上就是“Go语言中的Slice链式操作方法是什么”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯