aslist
aslist(A Sorted List)是golang語言實現的線程安全可排序的list。便捷的調用方式,使開發者快速入門使用。
前言
近來有噴子噴我,說golang有排序框架何苦要自己造輪子。我只想說中國的拿來主義思想就是導致今天中國爲何終始沒有自主研發的操作系統,沒有自己的芯片。你跟我說這句話就像問"已經有了Java爲什麼還要學Golang、爲什麼男人有了老婆還想有小三"。因爲需求嘛。各種各樣的需求,有人在乎性能,有人在乎便捷,有人在乎二者都在乎。你要是覺得我造的輪子不好,你自己就去造一個更好的。不要在這裏說一些顯得你很淺薄的話。aslist就是給在乎便捷、不想了解底層算法的人使用。不喜歡你可以走。
爲什麼要設計aslist?
如果你是從java轉golang開發,你就會發現golang中對數組(array)、切片(slice)的封裝比較原生。這對開發者來說過去java日常對List方便操作放在golang中是非常痛苦的。如排序(sort)、棧(stack)操作、先進先出(FIFO)、左進右出(LIRI)......本人深耕java多年深刻體會到你的痛苦,所以借鑑java對list體驗設計的思路封裝了這個輕量級的aslist。使你在golang中能找回java的感覺。
爲什麼Range、ClearTargets、Pop不能像Java一樣使用泛型?
沒有辦法,當前golang的泛型還沒有像Java一樣強大。先忍忍,估計馬上就要出來了。
快速開始
go get -u github.com/CreditTone/aslist
如果你使用gomod管理依賴
go get -u github.com/CreditTone/aslist@master
導入
import( "github.com/CreditTone/aslist" )
定義結構
type A struct { Name string }
1.創建aslist
asList := NewAsList()
2.push元素
asList.Push(A{Name: "我的名字好長"}) asList.Push(A{Name: "我名長"}) asList.Push(A{Name: "我的名字好長阿"}) asList.Push(A{Name: "我名字長"}) asList.Push(A{Name: "我的名字長"})
3.使用SortWithCompareFunc傳入自定義函數排序
asList := NewAsList() asList.Push(A{Name: "我的名字好長"}) asList.Push(A{Name: "我名長"}) asList.Push(A{Name: "我的名字好長阿"}) asList.Push(A{Name: "我名字長"}) asList.Push(A{Name: "我的名字長"}) t.Log("第一次遍歷") asList.Range(func(index int, item interface{}) bool { t.Log(index, item) return false //如果要中斷遍歷,請返回true }) asList.SortWithCompareFunc(func(a, b interface{}) bool { struct_a := a.(A) struct_b := b.(A) if len(struct_a.Name) > len(struct_b.Name) { return true //需要a 排在 b前面返回true } return false }) t.Log("排序後遍歷") asList.Range(func(index int, item interface{}) bool { t.Log(index, item) return false //如果要中斷遍歷,請返回true })
輸出結果:
=== RUN TestAsListSortWithCompareFunc
--- PASS: TestAsListSortWithCompareFunc (0.00s)
aslist_test.go:33: 第一次遍歷
aslist_test.go:35: 0 {我的名字好長}
aslist_test.go:35: 1 {我名長}
aslist_test.go:35: 2 {我的名字好長阿}
aslist_test.go:35: 3 {我名字長}
aslist_test.go:35: 4 {我的名字長}
aslist_test.go:45: 排序後遍歷
aslist_test.go:47: 0 {我的名字好長阿}
aslist_test.go:47: 1 {我的名字好長}
aslist_test.go:47: 2 {我的名字長}
aslist_test.go:47: 3 {我名字長}
aslist_test.go:47: 4 {我名長}
PASS
4.使用指針結構做元素也可以
asList := NewAsList() asList.Push(&A{Name: "我的名字好長"}) asList.Push(&A{Name: "我名長"}) asList.Push(&A{Name: "我的名字好長阿"}) asList.Push(&A{Name: "我名字長"}) asList.Push(&A{Name: "我的名字長"}) t.Log("第一次遍歷") asList.Range(func(index int, item interface{}) { t.Log(index, item) }) asList.SortWithCompareFunc(func(a, b interface{}) bool { struct_a := a.(*A) struct_b := b.(*A) if len(struct_a.Name) > len(struct_b.Name) { return true //需要a 排在 b前面返回true } return false }) t.Log("排序後遍歷") asList.Range(func(index int, item interface{}) { t.Log(index, item) })
輸出結果:
=== RUN TestStructPoint
--- PASS: TestStructPoint (0.00s)
aslist_test.go:60: 第一次遍歷
aslist_test.go:62: 0 &{我的名字好長}
aslist_test.go:62: 1 &{我名長}
aslist_test.go:62: 2 &{我的名字好長阿}
aslist_test.go:62: 3 &{我名字長}
aslist_test.go:62: 4 &{我的名字長}
aslist_test.go:72: 排序後遍歷
aslist_test.go:74: 0 &{我的名字好長阿}
aslist_test.go:74: 1 &{我的名字好長}
aslist_test.go:74: 2 &{我的名字長}
aslist_test.go:74: 3 &{我名字長}
aslist_test.go:74: 4 &{我名長}
PASS
5.數據結構實現Compare(a, b interface{}) bool方法可直接調用Sort排序
type B struct { Age int } func (self *B) Compare(a, b interface{}) bool { obj_a := a.(*B) obj_b := b.(*B) if obj_a.Age > obj_b.Age { return true } return false }
調用Sort方法排序
asList := NewAsList() asList.Push(&B{Age: 121}) asList.Push(&B{Age: 120}) asList.Push(&B{Age: 23}) asList.Push(&B{Age: 150}) asList.Push(&B{Age: 69}) t.Log("第一次遍歷") asList.Range(func(index int, item interface{}) bool { t.Log(index, item) return false //如果要中斷遍歷,請返回true }) asList.Sort() t.Log("排序後遍歷") asList.Range(func(index int, item interface{}) bool { t.Log(index, item) return false //如果要中斷遍歷,請返回true })
看到這裏有沒有java ArrayList.sort的感腳.輸出如下
=== RUN TestAutoSort
--- PASS: TestAutoSort (0.00s)
aslist_test.go:86: 第一次遍歷
aslist_test.go:88: 0 &{121}
aslist_test.go:88: 1 &{120}
aslist_test.go:88: 2 &{23}
aslist_test.go:88: 3 &{150}
aslist_test.go:88: 4 &{69}
aslist_test.go:91: 排序後遍歷
aslist_test.go:93: 0 &{150}
aslist_test.go:93: 1 &{121}
aslist_test.go:93: 2 &{120}
aslist_test.go:93: 3 &{69}
aslist_test.go:93: 4 &{23}
PASS
6.當你的AsList當中指針和結構體同時存在怎麼辦?這裏教你一個技巧巧妙的解決這個問題
//重新定義結構 type B struct { Age int } //定義一個BInterface來實現指針和結構體的多態 type BInterface interface { GetAge() int } //實現BInterface定義的方法,注意必須是(self B)不能是(self *B)。否則不能做到多態調用 func (self B) GetAge() int { return self.Age } //使用多態接口實現類型的統一轉換 func (self *B) Compare(a, b interface{}) bool { obj_a := a.(BInterface) obj_b := b.(BInterface) if obj_a.GetAge() > obj_b.GetAge() { return true } return false }
6.1測試多態設計思路
asList := NewAsList() asList.Push(&B{Age: 121}) asList.Push(B{Age: 120}) asList.Push(&B{Age: 23}) asList.Push(B{Age: 150}) asList.Push(B{Age: 69}) t.Log("第一次遍歷") asList.Range(func(index int, item interface{}) bool { t.Log(index, item) return false //如果要中斷遍歷,請返回true }) asList.Sort() t.Log("排序後遍歷") asList.Range(func(index int, item interface{}) bool { t.Log(index, item) return false //如果要中斷遍歷,請返回true })
輸出結果如下:
=== RUN TestPolymorphic
--- PASS: TestPolymorphic (0.00s)
aslist_test.go:134: 第一次遍歷
aslist_test.go:136: 0 &{121}
aslist_test.go:136: 1 {120}
aslist_test.go:136: 2 &{23}
aslist_test.go:136: 3 {150}
aslist_test.go:136: 4 {69}
aslist_test.go:140: 排序後遍歷
aslist_test.go:142: 0 {150}
aslist_test.go:142: 1 &{121}
aslist_test.go:142: 2 {120}
aslist_test.go:142: 3 {69}
aslist_test.go:142: 4 &{23}
PASS
7.實現唯一性校驗(Set)功能
asList := NewAsList() //設置GanerateUniqueId函數,asList將會做唯一性校驗 asList.GanerateUniqueId = func(i interface{}) string { bi := i.(BInterface) //假設以Age生成唯一id return fmt.Sprintf("%d", bi.GetAge()) } asList.Push(&B{Age: 121}) asList.Push(&B{Age: 120}) asList.Push(&B{Age: 23}) asList.Push(&B{Age: 150}) asList.Push(&B{Age: 69}) t.Log("測試唯一性功能,第一次遍歷") asList.Range(func(index int, item interface{}) bool { t.Log(index, item) return false //如果要中斷遍歷,請返回true }) asList.Push(&B{Age: 123}) asList.Push(&B{Age: 120}) //重複 asList.Push(&B{Age: 23}) //重複 asList.Push(&B{Age: 150}) //重複 asList.Push(&B{Age: 96}) t.Log("測試唯一性功能,第二次遍歷") asList.Range(func(index int, item interface{}) bool { t.Log(index, item) return false //如果要中斷遍歷,請返回true })
輸出結果如下:
=== RUN TestGanerateUniqueId
--- PASS: TestGanerateUniqueId (0.00s)
aslist_test.go:79: 測試唯一性功能,第一次遍歷
aslist_test.go:81: 0 &{121}
aslist_test.go:81: 1 &{120}
aslist_test.go:81: 2 &{23}
aslist_test.go:81: 3 &{150}
aslist_test.go:81: 4 &{69}
aslist_test.go:89: 測試唯一性功能,第二次遍歷
aslist_test.go:91: 0 &{121}
aslist_test.go:91: 1 &{120}
aslist_test.go:91: 2 &{23}
aslist_test.go:91: 3 &{150}
aslist_test.go:91: 4 &{69}
aslist_test.go:91: 5 &{123}
aslist_test.go:91: 6 &{96}
PASS
7.1也許你的結構體過於複雜,並且你不擅長寫生成唯一id的函數。沒有關係,aslist提供了兩個通用的函數供你選擇
b1 := B{Age: 1} b2 := &B{Age: 1} b3 := B{Age: 2} b4 := B{Age: 1} t.Log("SmartGanerateUniqueId,不忽略指針和結構體類型生成唯一id") //不忽略指針和結構體類型生成唯一id t.Log("b1", SmartGanerateUniqueId(b1)) t.Log("b2", SmartGanerateUniqueId(b2)) t.Log("b3", SmartGanerateUniqueId(b3)) t.Log("b4", SmartGanerateUniqueId(b4)) t.Log("SmartGanerateUniqueIdWithIgnorePoint,忽略指針和結構體類型生成唯一id") //忽略指針和結構體類型生成唯一id t.Log("b1", SmartGanerateUniqueIdWithIgnorePoint(b1)) t.Log("b2", SmartGanerateUniqueIdWithIgnorePoint(b2)) t.Log("b3", SmartGanerateUniqueIdWithIgnorePoint(b3)) t.Log("b4", SmartGanerateUniqueIdWithIgnorePoint(b4))
輸出結果如下:
=== RUN TestSmartGanerateUniqueId
--- PASS: TestSmartGanerateUniqueId (0.00s)
aslist_test.go:51: SmartGanerateUniqueId,不忽略指針和結構體類型生成唯一id
aslist_test.go:53: b1 40cf310cccaa86d9e0acc86a4a5e1fe3
aslist_test.go:54: b2 e65e33466c73b3c7ef6692759eb0c61b
aslist_test.go:55: b3 a3628aa02f4eda73de8106404d497476
aslist_test.go:56: b4 40cf310cccaa86d9e0acc86a4a5e1fe3
aslist_test.go:58: SmartGanerateUniqueIdWithIgnorePoint,忽略指針和結構體類型生成唯一id
aslist_test.go:60: b1 40cf310cccaa86d9e0acc86a4a5e1fe3
aslist_test.go:61: b2 40cf310cccaa86d9e0acc86a4a5e1fe3
aslist_test.go:62: b3 a3628aa02f4eda73de8106404d497476
aslist_test.go:63: b4 40cf310cccaa86d9e0acc86a4a5e1fe3
PASS
7.2測試aslist.SmartGanerateUniqueId
asList := NewAsList() //設置GanerateUniqueId函數,asList將會做唯一性校驗 asList.GanerateUniqueId = SmartGanerateUniqueId //aslist.SmartGanerateUniqueId,這裏我放的全是指針類型所以不必用SmartGanerateUniqueIdWithIgnorePoint。 asList.Push(&B{Age: 121}) asList.Push(&B{Age: 120}) asList.Push(&B{Age: 23}) asList.Push(&B{Age: 150}) asList.Push(&B{Age: 69}) t.Log("測試唯一性功能,第一次遍歷") asList.Range(func(index int, item interface{}) bool { t.Log(index, item) return false //如果要中斷遍歷,請返回true }) asList.Push(&B{Age: 123}) asList.Push(&B{Age: 120}) //重複 asList.Push(&B{Age: 23}) //重複 asList.Push(&B{Age: 150}) //重複 asList.Push(&B{Age: 96}) t.Log("測試唯一性功能,第二次遍歷") asList.Range(func(index int, item interface{}) bool { t.Log(index, item) return false //如果要中斷遍歷,請返回true })
輸出結果如下:
=== RUN TestGanerateUniqueIdWithSmartGanerateUniqueId
--- PASS: TestGanerateUniqueIdWithSmartGanerateUniqueId (0.00s)
aslist_test.go:105: 測試唯一性功能,第一次遍歷
aslist_test.go:107: 0 &{121}
aslist_test.go:107: 1 &{120}
aslist_test.go:107: 2 &{23}
aslist_test.go:107: 3 &{150}
aslist_test.go:107: 4 &{69}
aslist_test.go:115: 測試唯一性功能,第二次遍歷
aslist_test.go:117: 0 &{121}
aslist_test.go:117: 1 &{120}
aslist_test.go:117: 2 &{23}
aslist_test.go:117: 3 &{150}
aslist_test.go:117: 4 &{69}
aslist_test.go:117: 5 &{123}
aslist_test.go:117: 6 &{96}
PASS
8.隊列操作
asList := NewAsList() asList.Push(&B{Age: 121}) asList.Push(&B{Age: 120}) asList.Push(&B{Age: 23}) asList.Push(&B{Age: 150}) asList.Push(&B{Age: 69}) t.Log("第一次遍歷") asList.Range(func(index int, item interface{}) bool { t.Log(index, item) return false //如果要中斷遍歷,請返回true }) asList.Sort() t.Log("排序後遍歷") asList.Range(func(index int, item interface{}) bool { t.Log(index, item) return false //如果要中斷遍歷,請返回true }) for i := 1; i < 10; i++ { t.Log(fmt.Sprintf("第%d次pop:", i), asList.Pop()) }
輸出結果如下:
=== RUN TestQueue
--- PASS: TestQueue (0.00s)
aslist_test.go:105: 第一次遍歷
aslist_test.go:107: 0 &{121}
aslist_test.go:107: 1 &{120}
aslist_test.go:107: 2 &{23}
aslist_test.go:107: 3 &{150}
aslist_test.go:107: 4 &{69}
aslist_test.go:110: 排序後遍歷
aslist_test.go:112: 0 &{150}
aslist_test.go:112: 1 &{121}
aslist_test.go:112: 2 &{120}
aslist_test.go:112: 3 &{69}
aslist_test.go:112: 4 &{23}
aslist_test.go:115: 第1次pop: &{150}
aslist_test.go:115: 第2次pop: &{121}
aslist_test.go:115: 第3次pop: &{120}
aslist_test.go:115: 第4次pop: &{69}
aslist_test.go:115: 第5次pop: &{23}
aslist_test.go:115: 第6次pop: <nil>
aslist_test.go:115: 第7次pop: <nil>
aslist_test.go:115: 第8次pop: <nil>
aslist_test.go:115: 第9次pop: <nil>
PASS
9.序列化爲json
asList := NewAsList() asList.Push(&B{Age: 121}) asList.Push(&B{Age: 120}) asList.Push(&B{Age: 23}) asList.Push(&B{Age: 150}) asList.Push(&B{Age: 69}) t.Log("第一次MarshalJson") t.Log(string(asList.MarshalJson())) asList.Sort() t.Log("排序後MarshalJson") t.Log(string(asList.MarshalJson())) t.Log("RightPop:", asList.RightPop()) t.Log("LeftPop:", asList.LeftPop()) t.Log(string(asList.MarshalJson()))
輸出結果如下:
=== RUN TestMarshalJson
--- PASS: TestMarshalJson (0.00s)
aslist_test.go:126: 第一次MarshalJson
aslist_test.go:127: [{"Age":121},{"Age":120},{"Age":23},{"Age":150},{"Age":69}]
aslist_test.go:129: 排序後MarshalJson
aslist_test.go:130: [{"Age":150},{"Age":121},{"Age":120},{"Age":69},{"Age":23}]
aslist_test.go:131: RightPop: &{23}
aslist_test.go:132: LeftPop: &{150}
aslist_test.go:133: [{"Age":121},{"Age":120},{"Age":69}]
PASS
10.反序列化json
list := []interface{}{} list = append(list, &B{Age: 121}, &B{Age: 120}, &B{Age: 23}, &B{Age: 150}, &B{Age: 69}) listJson, _ := json.Marshal(list) //加載json asList := NewAsList() asList.Push(&B{Age: 89}) //true表示需要追加 unSerialize反序列化的函數 err := asList.UnmarshalJson(listJson, true, func(itemData []byte) interface{} { item := new(B) json.Unmarshal(itemData, item) return item }) if err != nil { t.Error(err) return } t.Log("UnmarshalJson後遍歷") asList.Range(func(index int, item interface{}) bool { t.Log(index, item) return false //如果要中斷遍歷,請返回true })
輸出結果如下:
=== RUN TestUnMarshalJson
--- PASS: TestUnMarshalJson (0.00s)
aslist_test.go:163: UnmarshalJson後遍歷
aslist_test.go:165: 0 &{89}
aslist_test.go:165: 1 &{121}
aslist_test.go:165: 2 &{120}
aslist_test.go:165: 3 &{23}
aslist_test.go:165: 4 &{150}
aslist_test.go:165: 5 &{69}
PASS
11.ClearTargets和Clear
asList := NewAsList() asList.Push(&B{Age: 121}) asList.Push(&B{Age: 120}) asList.Push(&B{Age: 23}) asList.Push(&B{Age: 150}) asList.Push(&B{Age: 69}) t.Log("第一次遍歷") asList.Range(func(index int, item interface{}) bool { t.Log(index, item) return false //如果要中斷遍歷,請返回true }) asList.ClearTargets(func(index int, item interface{}) bool { struct_a := item.(*B) //把小於Age小於100的全部清除掉 if struct_a.Age < 100 { return true } return false }) t.Log("ClearTargets後遍歷") asList.Range(func(index int, item interface{}) bool { t.Log(index, item) return false //如果要中斷遍歷,請返回true }) asList.Clear() //清除所有元素 t.Log("Clear後元素個數爲", asList.Length())
輸出結果如下:
=== RUN TestClear
--- PASS: TestClear (0.00s)
aslist_test.go:166: 第一次遍歷
aslist_test.go:168: 0 &{121}
aslist_test.go:168: 1 &{120}
aslist_test.go:168: 2 &{23}
aslist_test.go:168: 3 &{150}
aslist_test.go:168: 4 &{69}
aslist_test.go:179: ClearTargets後遍歷
aslist_test.go:181: 0 &{121}
aslist_test.go:181: 1 &{120}
aslist_test.go:181: 2 &{150}
aslist_test.go:185: Clear後元素個數爲 0
PASS