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

Go Map 加有序排序的一些掙扎

開發(fā) 前端
雖然社區(qū)很多人提過很多種不同的建議。但,顯然,Go 核心團隊不是無法實現(xiàn)一個帶穩(wěn)定排序的 map 類型。為此在實現(xiàn)上要付出較高的改造代價和性能、開銷風(fēng)險。外加 less is more 的設(shè)計哲學(xué)。導(dǎo)致此項功能特性一直停滯不前。

大家好,我是煎魚。

最近我有一個朋友又跟 map 扯上關(guān)系了,翻了個車。寫 Go 項目真的是和 map 藕斷絲連,時刻要注意。

今天看到社區(qū)內(nèi) map 加有序排序又各種掙扎過好幾輪。今天拋磚引玉??纯创蠹矣袥]有好的思路。

快速背景

Go 提供了一種內(nèi)置的 map 類型,它實現(xiàn)了一個哈希表,在 Go 程序中普遍應(yīng)用廣泛,能夠做一系列的增刪改查。

類型簽名如下:

map[KeyType]ValueType

最小演示代碼:

func main() {
 m := make(map[int32]string)
 m[0] = "煎魚1"
 m[1] = "煎魚2"
 m[2] = "煎魚3"
 m[3] = "煎魚4"
 m[4] = "煎魚5"
 m[5] = "煎魚6"
 for k, v := range m {
  log.Printf("k: %v, v: %v", k, v)
 }
}

輸出結(jié)果:

$ go run demo.go
2023/12/28 23:36:02 k: 2, v: 煎魚3
2023/12/28 23:36:02 k: 3, v: 煎魚4
2023/12/28 23:36:02 k: 4, v: 煎魚5
2023/12/28 23:36:02 k: 5, v: 煎魚6
2023/12/28 23:36:02 k: 0, v: 煎魚1
2023/12/28 23:36:02 k: 1, v: 煎魚2

輸出結(jié)果看著沒有什么問題。但細心查看的同學(xué)應(yīng)該發(fā)現(xiàn)了。在遍歷 map 類型時,訪問結(jié)果是無序的。明顯多執(zhí)行幾次就會發(fā)現(xiàn)與我們聲明的順序不一致。

社區(qū)討論

這可不。這么尷尬的無序結(jié)果。對于初學(xué)者而言很容易導(dǎo)致潛在的 BUG,引發(fā)一些問題/事故。

大家為此做出過努力。提出過各種提案。例如:

  • 《proposal: Go 2: add native type for map that maintains key order[1]》
  • 《proposal: add string key sorted map as built in type[2]》
  • 《proposal: Add a sorting function for map[3]》

基于這些提案,也有人提出了新的關(guān)鍵字 sortedMap:

type User struct{
   UserId string
   Name string
}

func main(){
  db := sortedMap[string]*User{}
  db["煎魚2"] = &User{UserId:"煎魚2",Name:"n2"}
  db["煎魚1"] = &User{UserId:"煎魚1",Name:"n1"}
  for userId, user := range db {
    fmt.Println(userId, user.Name)
  }

  // should output
  // 煎魚1 n1
  // 煎魚2 n2
}

但最終都失敗告終。原因不外乎以下幾類原因:

  • Go1 兼容性保障規(guī)范:對 map 類型從無序改到有序,必然會存在破壞性變更。這活現(xiàn)在干不了。以后未來的 Go2 再說吧(拖字訣)。
  • 排序后 map 的速度慢:如果將默認映射類型改為排序映射,那么不需要排序映射實現(xiàn)或已編寫代碼在需要時對鍵進行排序的人都會受到懲罰。(via @Dave Cheney)
  • 實現(xiàn)穩(wěn)定排序的 map 麻煩:Go 在標(biāo)準(zhǔn)庫 fmt 里實現(xiàn)了穩(wěn)定排序的 map 輸出,整體實現(xiàn)較為難以解決。言外之意不建議將穩(wěn)定排序加入 map 類型的支持內(nèi)。(via @Rob Pike)

參考實現(xiàn)

Go 核心團隊推薦查看:https://github.com/golang/go/blob/master/src/internal/fmtsort/sort.go 的實現(xiàn)邏輯。如果要對 map 類型做穩(wěn)定排序。要做一樣的事情,甚至更多。

說白了,就是要做大小對比、順序排序。還要適配所有的類型。

對應(yīng)源代碼的其中一角:

type SortedMap struct {
 Key   []reflect.Value
 Value []reflect.Value
}

func (o *SortedMap) Len() int           { return len(o.Key) }
func (o *SortedMap) Less(i, j int) bool { return compare(o.Key[i], o.Key[j]) < 0 }
func (o *SortedMap) Swap(i, j int) {
 o.Key[i], o.Key[j] = o.Key[j], o.Key[i]
 o.Value[i], o.Value[j] = o.Value[j], o.Value[i]
}

func Sort(mapValue reflect.Value) *SortedMap {
 if mapValue.Type().Kind() != reflect.Map {
  return nil
 }

 n := mapValue.Len()
 key := make([]reflect.Value, 0, n)
 value := make([]reflect.Value, 0, n)
 iter := mapValue.MapRange()
 for iter.Next() {
  key = append(key, iter.Key())
  value = append(value, iter.Value())
 }
 sorted := &SortedMap{
  Key:   key,
  Value: value,
 }
 sort.Stable(sorted)
 return sorted
}

func compare(aVal, bVal reflect.Value) int {
 aType, bType := aVal.Type(), bVal.Type()
 if aType != bType {
  return -1 // No good answer possible, but don't return 0: they're not equal.
 }
 switch aVal.Kind() {
 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  a, b := aVal.Int(), bVal.Int()
  switch {
  case a < b:
   return -1
  case a > b:
   return 1
  default:
   return 0
  }
 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:

  ...

}

如果只是標(biāo)準(zhǔn)庫 fmt 輸出流用到,常規(guī)的實現(xiàn)就行。但如果內(nèi)置到 map 類型中,就還要考量性能、開銷、可維護性的綜合因素。折騰起來也是不太妙的,會引入不少的復(fù)雜度。

總結(jié)

雖然社區(qū)很多人提過很多種不同的建議。但,顯然,Go 核心團隊不是無法實現(xiàn)一個帶穩(wěn)定排序的 map 類型。

為此在實現(xiàn)上要付出較高的改造代價和性能、開銷風(fēng)險。外加 less is more 的設(shè)計哲學(xué)。導(dǎo)致此項功能特性一直停滯不前。

這個大背景下,大家也慢慢還是選擇了第三條路。使用第三方庫,或者配合 slice 來做,要不就是基于近年的泛型來實現(xiàn)了。

參考資料

[1]proposal: Go 2: add native type for map that maintains key order: https://github.com/golang/go/issues/41289

[2]proposal: add string key sorted map as built in type: https://github.com/golang/go/issues/22865

[3]proposal: Add a sorting function for map: https://github.com/golang/go/issues/39291

責(zé)任編輯:武曉燕 來源: 腦子進煎魚了
相關(guān)推薦

2020-10-12 08:03:51

Go語言編程

2022-11-03 09:28:20

GoFrameGomap

2021-09-27 10:04:03

Go程序處理

2021-09-27 15:33:48

Go 開發(fā)技術(shù)

2021-02-20 17:16:39

Go語言Go開發(fā)者編程

2009-06-18 14:54:52

Spring AOP

2013-07-02 10:18:20

編程編程策略

2020-02-03 16:03:36

疫情思考

2016-11-16 21:18:42

android日志

2009-09-21 17:46:25

Hibernate數(shù)據(jù)

2013-07-02 09:43:02

編程策略

2011-06-01 16:50:21

JAVA

2010-09-28 14:14:19

SQL語句

2009-06-25 09:50:32

JSF

2009-07-21 09:55:45

iBATIS分頁

2012-05-21 10:13:05

XCode調(diào)試技巧

2011-07-13 09:13:56

Android設(shè)計

2011-03-15 17:46:43

2013-03-29 13:17:53

XCode調(diào)試技巧iOS開發(fā)

2021-06-08 06:13:16

React開發(fā)開發(fā)技術(shù)
點贊
收藏

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