欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Go語言中的Slice鏈式操作

 更新時間:2023年04月07日 16:32:21   作者:cipher  
這篇文章主要為大家詳細介紹了Go語言中的Slice鏈式操作的相關知識,文中的示例代碼講解詳細,具有一定的學習價值,感興趣的小伙伴可以了解一下

示例

首先模擬一個業(yè)務場景,有訂單、產品、自定義訂單三個結構體,訂單中包含多個產品:

type Order struct {
	Id       string
	Products []Product
}

type Product struct {
	Id    string
	Price int
}

type CustomOrder struct {
	Id string
}

初始化模擬數(shù)據(jù):

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 類型切片,方便后面的業(yè)務邏輯使用。

因為 go 不支持在接受者函數(shù)中定義泛型,因此所有操作函數(shù)的參數(shù)和返回值類型只能定義為any,然后在函數(shù)體內轉換為業(yè)務結構體使用,例如上面的 i.(Product).Price。

此后將每一種操作,例如Filter、Map、Flat等,都返回List[T] 結構體,就可以實現(xiàn)鏈式操作。

實現(xiàn)

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 = l
	return 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 T
		return 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鏈式操作的文章就介紹到這了,更多相關Go Slice鏈式操作內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • go實現(xiàn)for range迭代時修改值的操作

    go實現(xiàn)for range迭代時修改值的操作

    這篇文章主要介紹了go實現(xiàn)for range迭代時修改值的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Go語言學習之context包的用法詳解

    Go語言學習之context包的用法詳解

    日常Go開發(fā)中,Context包是用的最多的一個了,幾乎所有函數(shù)的第一個參數(shù)都是ctx,那么我們?yōu)槭裁匆獋鬟fContext呢,Context又有哪些用法,底層實現(xiàn)是如何呢?相信你也一定會有探索的欲望,那么就跟著本篇文章,一起來學習吧
    2022-10-10
  • go原生庫的中bytes.Buffer用法

    go原生庫的中bytes.Buffer用法

    這篇文章主要介紹了go原生庫的中bytes.Buffer用法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • 基于Go編寫一個可視化Navicat本地密碼解析器

    基于Go編寫一個可視化Navicat本地密碼解析器

    這篇文章主要給大家介紹了基于Go編寫一個可視化Navicat本地密碼解析器的方法,文中有詳細的代碼示例和圖文介紹,有需要的朋友可以參考閱讀本文
    2023-08-08
  • Golang使用MinIO的方案詳解

    Golang使用MinIO的方案詳解

    這篇文章主要介紹了Golang使用MinIO的過程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-08-08
  • 基于golang如何實現(xiàn)error工具包詳解

    基于golang如何實現(xiàn)error工具包詳解

    Go 語言使用 error 類型來返回函數(shù)執(zhí)行過程中遇到的錯誤,下面這篇文章主要給大家介紹了關于如何基于golang實現(xiàn)error工具包的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2018-09-09
  • Go語言七篇入門教程一簡介初識

    Go語言七篇入門教程一簡介初識

    本篇是Go語言七篇入門系列第一篇Go語言初識及簡單介紹,從現(xiàn)在開始一起打開Go語言的學習大門吧,希望能夠有所幫助,祝大家多多進步
    2021-11-11
  • 深入了解Go語言中sync.Pool的使用

    深入了解Go語言中sync.Pool的使用

    本文將介紹?Go?語言中的?sync.Pool并發(fā)原語,包括sync.Pool的基本使用方法、使用注意事項等的內容,對我們了解Go語言有一定的幫助,需要的可以參考一下
    2023-04-04
  • golang之反射和斷言的具體使用

    golang之反射和斷言的具體使用

    這篇文章主要介紹了golang之反射和斷言的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-10-10
  • Go爬蟲(http、goquery和colly)詳解

    Go爬蟲(http、goquery和colly)詳解

    goquery可以避免操作復雜的正則表達式,它可以直接根據(jù)url獲取一個Document對象,然后根據(jù)標簽選擇器、類選擇器和id選擇器獲取相應的選擇對象,進行自定義的操作,這篇文章主要介紹了Go爬蟲(http、goquery和colly),需要的朋友可以參考下
    2022-09-09

最新評論