自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一個(gè)能讓你少寫循環(huán)和判斷的Go開源包,支持范型

開發(fā) 前端
今天介紹的lo?庫大家可以嘗試用起來,等用習(xí)慣了確實(shí)能讓自己的代碼少寫不少循環(huán)加判斷的邏輯,整體風(fēng)格會(huì)更清爽,自己也能少寫一些代碼。如果你們還在用的Go版本不支持范型,可以嘗試用一下風(fēng)格類似的庫go-funk。

大家在開發(fā)項(xiàng)目寫代碼的時(shí)候,最常用到的數(shù)據(jù)類型應(yīng)該是列表,比如從數(shù)據(jù)庫查詢一個(gè)用戶的訂單,查詢結(jié)果會(huì)以一個(gè)對象列表的形式返回給調(diào)用程序。

[]*Order {
    &{
        ID: 1,
        OrderNo: "20240903628359373756980001"
        ...
    },
    ...
}

有了結(jié)果集列表之后,大部分時(shí)候?yàn)榱藢?shí)現(xiàn)產(chǎn)品邏輯我們需要在這個(gè)列表的基礎(chǔ)上進(jìn)行判斷、篩選和加工出自己想要的數(shù)據(jù)集。

因?yàn)榱斜硎嵌鄠€(gè)同類數(shù)據(jù)的集合,這些操作都需要我們在遍歷列表的基礎(chǔ)上來完成,比如判斷 ID 為1 的訂單在不在列表中。

......
var exists bool
for _, order := range orders {
    if order.ID == 1 {
        exists = true
    }
}
...

當(dāng)然,為了減少遍歷次數(shù),我們通常會(huì)先通過一次遍歷生成一個(gè)以數(shù)據(jù)主鍵為Key的哈希Map:

map[int64]Order {
    "1": {
       ID: 1,
       OrderNo: "20240903628359373756980001"
       ... 
    }
}

列表和哈希Map在Go里的類型是Slice 和 Map,上面這些操作應(yīng)該是大家寫代碼的時(shí)候,差不多每天都會(huì)遇到的情況。比如,從Slice切片中查找一個(gè)元素的位置、查找一個(gè)元素是不是存在、查找所有滿足條件的元素,又比如獲取Map的所有key、所有的value、還有像上面說的把Slice 轉(zhuǎn)換成 Map。

這些操作在所有編程語言里都很常見,比如Javascript里數(shù)組的map、reduce、filter函數(shù),Java 的 Stream API在編程中都非常好用,但是遺憾的是Go標(biāo)準(zhǔn)庫沒有提供類似的功能。

為了不在每個(gè)函數(shù)里都寫一遍,很多項(xiàng)目里會(huì)編寫大量的工具函數(shù)來進(jìn)行Slice和Map數(shù)據(jù)的處理,相信你一定在自己寫過的項(xiàng)目里見過一個(gè)叫 util的包,里面寫了各種 InSlice, InArray, XXXInSlice 等等之類的工具函數(shù)。

當(dāng)然這些也不用每次做項(xiàng)目都寫一遍,大部分通用的可以先從老項(xiàng)目粘到新項(xiàng)目里去。。。但是Go以前不支持范性,這種工具函數(shù)針對項(xiàng)目用到的自定義類型都寫一遍也是一個(gè)問題,時(shí)間長了也需要人來維護(hù)。

還有一種方式是使用社區(qū)里經(jīng)過充分的測試、驗(yàn)證,并且經(jīng)常更新的開源庫,在Go 1.18 版本以前比較有名的函數(shù)庫是go-funk,它提供了很多好用的函數(shù):Contains、Difference、IndexOf、Filter、ToMap等等,更多的可以參考它的網(wǎng)站:https://github.com/thoas/go-funk

因?yàn)樗窃贕o1.18 以前出來的,所以不可避免的會(huì)用到反射來處理多類型適配的問題,舉個(gè)Contains,即判斷是不是 InSlice的例子,假如不用反射,要多類型使用,就得定義很多相似名稱的函數(shù)。

func ContainsInt(collection []int, x int) bool {

}

func ContainsString(collection []string, x string) bool {

}

這跟咱們自己寫工具函數(shù)就沒什么區(qū)別了,在Go語言的泛型支持之前,要解決這個(gè)問題就能用反射。假如你們現(xiàn)在的項(xiàng)目還在用Go1.18 以前的版本,又不想寫自己手寫那么多循環(huán)和判斷代碼,那還是就用go-funk吧。

Go 1.18 支持了范型以后,很快就有人用范型寫出了與go-funk功能相同的函數(shù)包,這個(gè)包就是今天要介紹的主角,它叫 lo,名字有點(diǎn)怪,但是簡介里已經(jīng)寫清楚了它的用途: A Lodash-style Go library based on Go 1.18+ Generics (map, filter, contains, find...)

一個(gè)基于 Go 1.18+ 的范型,提供 map, filter, contains, find... 等操作的,類似 JS Lodash 工具包風(fēng)格的工具包,哈哈哈,翻譯過來字兒有點(diǎn)多。

它是基于泛型實(shí)現(xiàn),沒有用到反射,效率更高,代碼也更簡潔。比如剛才說的Contains函數(shù),是這么實(shí)現(xiàn)的:

func Contains[T comparable](collection []T, element T) bool {
 for i := range collection {
  if collection[i] == element {
   return true
  }
 }

 return false
}

只需要 T 被約束為 comparable 的,就可以使用==符號(hào)進(jìn)行比較了,整體代碼非常簡單,如果你自己寫代碼的時(shí)候需要用到范型,可以先學(xué)習(xí)學(xué)習(xí)它源碼中對Go范型的各種使用。

接下來我給大家演示一些我們常用到的操作使用 lo 庫的工具函數(shù)時(shí)應(yīng)該怎么寫。

常用的Slice 和 Map 操作

首先 lo 庫里提供了非常多的關(guān)于 Slice、Map、String、Channel 的操作, 不過官方給的例子比較簡單都是針對Int、String 切片這樣基礎(chǔ)類型集合的操作,我這里給大家演示一些我們實(shí)際開發(fā)時(shí)會(huì)用到的關(guān)于[]*Order 這樣的自定義類型的Slice 和 Map 的操作。

Filter 篩選符合條件的子列表

假如我們有一個(gè)像下面這樣的訂單列表

[]*Order {
    &{
        ID: 1,
        OrderNo: "20240903628359373756980001"
        UserId: 255
        ...
    },
    ...
}

我們要篩選出訂單列表中 UserId 字段值等于參數(shù) userId 的所有元素。

func FindUserOrders(orders []*Order, userId int64) []*Order { 
    
    userOrders := lo.Filter(orders, func(item *Order, index int) bool {
      return item.UserId == userId
    })

    return userOrders
}

從訂單列表中提取出所有訂單ID

有的時(shí)候我們希望從列表中提取出所有ID,再去做進(jìn)一步的數(shù)據(jù)庫的 IN (idList) 的查詢,這個(gè)時(shí)候我們可以使用Map 函數(shù)。

orderIds := lo.Map(orders, func(item *Order, index int) int64 {
    return item.ID
})

把列表轉(zhuǎn)換成Map

文章開頭提到過,很多時(shí)候?yàn)榱藴p少遍歷次數(shù)會(huì)有把列表轉(zhuǎn)換成以ID 為 Key Map的需求,這個(gè)時(shí)候我們可以使用 lo 庫的 SliceToMap 來實(shí)現(xiàn)

orderMap := lo.SliceToMap(orders, func(item *Order) (int64, *Order) {
    return item.ID, item
})

讓列表按字段進(jìn)行分組

如果你想讓上面的訂單列表按照 UserId 分組歸類,變成一個(gè) Key 是 UserId 值是用戶所有訂單的列表的 Map

map[int64][]*Order{
    255: [
       &{
            ID: 1,
           OrderNo: "20240903628359373756980001"
           UserId: 255
           ...
        }
        ...
    ]
    ... 
}

我們可以使用 lo 庫的GroupBy方法來實(shí)現(xiàn)

userOrderMap = lo.GroupBy(orders, func(item *Order) int64 {
    return item.UserId
})

Reduce 求加和

比如我們要求所有訂單金額的總和,可以使用 lo.Reduce 函數(shù)

// 計(jì)算總價(jià)
totalPrice := lo.Reduce(orders, func(agg int, item *Order, index int) int {
  return agg + item.PayMoney
}, 0)

多線程Foreach

lo 包里除了提供了 Foreach 功能函數(shù)來遍歷集合

lo.ForEach([]string{"hello", "world"}, func(x string, _ int) {
    println(x)
})

除此之外還可以用多個(gè)goroutine 來進(jìn)行遍歷,不過要安裝它的一個(gè)子包。

import lop "github.com/samber/lo/parallel"

lop.ForEach([]string{"hello", "world"}, func(x string, _ int) {
    println(x)
})

這個(gè)說實(shí)話我沒有用過,如果你有一個(gè)超大的集合要遍歷可以嘗試一下。

Map 的常用操作中

lo 包中也有很多 Map 類型的操作功能,像 Keys、UniqKeys、Values、UniqValues 等等,其實(shí)各種功能的名字基本上跟其他語言提供的庫函數(shù)的名字類似,相信通過我上面的演示后大家完全可以自己探索,找到自己需要的功能了。

關(guān)于 lo 庫更多的功能,大家參考它的官方文檔吧:https://github.com/samber/lo 接下來我說說使用它編碼時(shí)的一些建議。

東西雖好,可別貪杯

關(guān)于 lo 庫的使用,我覺得能用一個(gè)簡單循環(huán)實(shí)現(xiàn)的邏輯就不用小題大做地來使用 lo 庫里的功能了,假如像是上面舉例的情況那樣,自己寫代碼要循環(huán)加判斷再加額外的變量賦值才能搞定,建議是 lo 庫里的功能,確實(shí)能讓少寫代碼,而且讓整個(gè)代碼塊的嵌套層次不會(huì)深,整體看上去會(huì)簡潔一些。

另外我覺得是,這些功能不要嵌套著用,本來就是函數(shù)式編程的風(fēng)格,再嵌套著用就很難看懂了。

以前我學(xué)Java的時(shí)候,覺得Java那個(gè) Stream API真的很方便,還能鏈?zhǔn)秸{(diào)用,寫起來很爽。可是輪到自己維護(hù)前人寫的項(xiàng)目的時(shí)候,一來實(shí)際的業(yè)務(wù)邏輯本來就比書上的例子復(fù)雜,這些代碼邏輯一頓Stream API鏈?zhǔn)秸{(diào)用,再加上用了 lambda,那代碼看起來真的是每次都要讀很久才能明白是在干啥。

比如下面這段代碼,不看注釋、不翻翻Java的Stream 和 Lambda 語法你能看明白這塊代碼是做什么的嗎?

// 求兩個(gè)List, aList 與 bList 的交集 
List<Person> intersections = aList
        .stream().filter(
                a ->  bList.stream().map(Person::getId)
                .anyMatch( 
                    id -> Objects.equals(a.getId(), id)
                )
        ).collect(Collectors.toList());

總結(jié)

今天介紹的lo庫大家可以嘗試用起來,等用習(xí)慣了確實(shí)能讓自己的代碼少寫不少循環(huán)加判斷的邏輯,整體風(fēng)格會(huì)更清爽,自己也能少寫一些代碼。如果你們還在用的Go版本不支持范型,可以嘗試用一下風(fēng)格類似的庫go-funk。

責(zé)任編輯:武曉燕 來源: 網(wǎng)管叨bi叨
相關(guān)推薦

2020-04-10 10:15:29

算法開源Github

2016-12-19 10:22:05

代碼正則表達(dá)式

2023-06-14 08:02:54

函數(shù)代碼概率

2023-11-30 08:21:33

2017-03-31 09:35:14

Android函數(shù)Android庫

2024-03-18 08:06:59

JavaGo開發(fā)

2019-07-10 12:55:23

正則表達(dá)式代碼語法

2024-03-22 08:51:36

分庫分表項(xiàng)目

2023-07-17 08:10:54

結(jié)構(gòu)體Env

2023-05-15 08:30:35

YjsReact

2016-10-26 19:05:02

2020-11-04 09:56:13

開源技術(shù) go

2013-08-09 09:49:19

開源怎么開源庫開源

2025-01-15 10:44:55

Go泛型接口

2022-09-19 08:07:28

Goweb 程序

2021-08-13 11:45:00

Go語言字節(jié)

2021-03-10 10:00:31

Go語言strconv包類型轉(zhuǎn)換工具

2023-02-06 06:21:53

BookStack開源

2021-08-23 11:35:37

代碼開發(fā)開源

2021-09-26 05:25:33

邊緣計(jì)算IoT
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)