最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語言中關(guān)于set的實(shí)現(xiàn)思考分析

 更新時(shí)間:2024年01月18日 08:12:16   作者:visforest  
Go?開發(fā)過程中有時(shí)我們需要集合(set)這種容器,但?Go?本身未內(nèi)置這種數(shù)據(jù)容器,故常常我們需要自己實(shí)現(xiàn),下面我們就來看看具體有哪些實(shí)現(xiàn)方法吧

Go 開發(fā)過程中有時(shí)我們需要集合(set)這種容器,但 Go 本身未內(nèi)置這種數(shù)據(jù)容器,故常常我們需要自己實(shí)現(xiàn),其實(shí)實(shí)現(xiàn)也很簡(jiǎn)單。

附,推薦閱讀:github.com/Visforest/goset

map[xxx]struct{}

最常用和最容易想到的實(shí)現(xiàn)是使用 map,如:

type StrSet struct{
    data map[string]struct{}
}

map 的 value 部分設(shè)計(jì)為 struct{} 類型是為了節(jié)省內(nèi)存空間。

map[interface{}]struct{}

上面實(shí)現(xiàn)的是 string 的 set,如果要其他類型的 set 就得再定義 Int8Set、IntSetFloat32Set 等等,很是繁瑣。

很多人可能會(huì)選擇這樣實(shí)現(xiàn) :

type Set struct {
	data map[interface{}]struct{}
}

// New creates a new Set
func New(v ...interface{}) *Set {
	s := &Set{data: map[interface{}]struct{}{}}
	for _, ele := range v {
		s.data[ele] = struct{}{}
	}
	return s
}

// ...

// ToList returns data slice
func (s *Set) ToList() []interface{} {
	var data = make([]interface{}, len(s.data))
	var i int
	for d := range s.data {
		data[i] = d
		i++
	}
	return data
}

這種方式有幾個(gè)問題:

執(zhí)行如下代碼:

func main() {
	var l1 = []int{1, 2, 3}
	var l2 = []int{4, 5, 6}
	var s = NewSet(l1, l2)
	for _, e := range s.ToList() {
		fmt.Println(e)
	}
}

出錯(cuò):

panic: runtime error: hash of unhashable type []int

原因很簡(jiǎn)單,[]int 是不能被 hash 計(jì)算的,即不能作為 map 的 key,讀者可以查閱 map key允許的類型。interface{} 這種“萬金油” 也可能是不合適的。

觀察下面代碼

func main() {
	var s = NewSet("a", "b", "c")
	var tmp []string
	for _, e := range s.ToList() {
		tmp = append(tmp, e.(string))
	}
	test(tmp)
}

test 函數(shù)不能直接拿 s.ToList() 作為入?yún)ⅲ仨殞?s.ToList() 進(jìn)行轉(zhuǎn)換為 []string,原因不言自明。

每次都要轉(zhuǎn)換明顯損失了編碼效率和執(zhí)行效率。

map[T comparable]struct{}

上面的弊端,可以用 泛型(generics)解決。

定義:

type Set[T comparable] struct {
	data map[T]struct{}
}

// New creates a new Set
func NewSet[T comparable](v ...T) *Set[T] {
	s := &Set[T]{data: map[T]struct{}{}}
	for _, ele := range v {
		s.data[ele] = struct{}{}
	}
	return s
}

func (s *Set[T]) Add(v ...T) {
	for _, ele := range v {
		s.data[ele] = struct{}{}
	}
}

// ...

// ToList returns data slice
func (s *Set[T]) ToList() []T {
	var data = make([]T, len(s.data))
	var i int
	for d := range s.data {
		data[i] = d
		i++
	}
	return data
}

使用:

func test1(data []string) {
	// ...
}

func test2(data []float64) {
	// ...
}

func main() {
	var s1 = NewSet("a", "b", "c")
	test1(s1.ToList())

	var s2 = NewSet(1.3, 2.2, 3)
	test2(s2.ToList())
}

type IntSet = Set[int]

上面的 Set 是個(gè)通用 set,類型混用時(shí)自己可能會(huì)被誤導(dǎo)。我們可以定義專用數(shù)據(jù)類型的 set,且代碼不需要很多。

type IntSet = Set[int]

func NewIntSet(v ...int) *IntSet {
	return NewSet[int](v...)
}

使用:

func main() {
	var s = NewIntSet(1, 2, 3)
	test3(s.ToList())

	// 編譯錯(cuò)誤
	// s.Add("a", "b", "c")
}

fifo set

通常 set 是無序的,上面的實(shí)現(xiàn)也都是無序的,但有的場(chǎng)景下我們需要有序的 set,比如fifo set,sorted set。這里以 fifo set 為例,討論下其實(shí)現(xiàn)。

為了兼顧查找效率和有序特性,可以使用 map + array / double linkedlist,考慮到數(shù)據(jù)的添加、刪除以及內(nèi)存使用,double linkedlist 有比 array 顯著的優(yōu)勢(shì)。

type setNode[T comparable] struct {
	val  T
	pre  *setNode[T]
	next *setNode[T]
}

type FifoSet[T comparable] struct {
	head *setNode[T]
	tail *setNode[T]
	data map[T]*setNode[T]
}

// add data, make it first in first out
func (l *FifoSet[T]) Add(v ...T) {
	if len(v) == 0 {
		return
	}

	var i int
	if l.head == nil {
		// first node
		n := &setNode[T]{
			val: v[i],
		}
		l.head = n
		l.tail = n
		l.data[v[i]] = n
		i++
	}
	for ; i < len(v); i++ {
		if _, ok := l.data[v[i]]; !ok {
            // when missing, insert
			n := &setNode[T]{
				val:  v[i],
				pre:  l.tail,
				next: nil,
			}
			l.tail.next = n
			l.tail = n
			l.data[v[i]] = n
		}
	}
}

使用:

func main() {
	var s = NewFifoSet[string]()
	s.Add("e", "a", "b", "a", "c", "b")
	// e
	// a
    // b
	// c
	for _, v := range s.ToList() {
		fmt.Println(v)
	}
}

sorted set

其實(shí) sorted set 與 fifo set 實(shí)現(xiàn)很像,只是略有區(qū)別,這里就略過了。

有興趣的可以閱讀筆者的 github.com/Visforest/goset,或者自己嘗試自己實(shí)現(xiàn)下。

以上就是Go語言中關(guān)于set的實(shí)現(xiàn)思考分析的詳細(xì)內(nèi)容,更多關(guān)于Go set的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解go中的defer鏈如何被遍歷執(zhí)行

    詳解go中的defer鏈如何被遍歷執(zhí)行

    為了在退出函數(shù)前執(zhí)行一些資源清理的操作,例如關(guān)閉文件、釋放連接、釋放鎖資源等,會(huì)在函數(shù)里寫上多個(gè)defer語句,多個(gè)_defer 結(jié)構(gòu)體形成一個(gè)鏈表,G 結(jié)構(gòu)體中某個(gè)字段指向此鏈表,那么go中的defer鏈如何被遍歷執(zhí)行,本文將給大家詳細(xì)的介紹,感興趣的朋友可以參考下
    2024-01-01
  • 使用Go語言統(tǒng)計(jì)文件中每個(gè)字母出現(xiàn)頻率的方法

    使用Go語言統(tǒng)計(jì)文件中每個(gè)字母出現(xiàn)頻率的方法

    這篇文章主要介紹了如何使用Go語言統(tǒng)計(jì)文件中每個(gè)字母出現(xiàn)頻率 的完整內(nèi)容,本案例適合用來練習(xí)文件讀取、字符處理、map統(tǒng)計(jì)等基礎(chǔ)技能,感興趣的小伙伴跟著小編一起來看看吧
    2025-07-07
  • Golang?單元測(cè)試和基準(zhǔn)測(cè)試實(shí)例詳解

    Golang?單元測(cè)試和基準(zhǔn)測(cè)試實(shí)例詳解

    這篇文章主要為大家介紹了Golang?單元測(cè)試和基準(zhǔn)測(cè)試實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • grpcurl通過命令行訪問gRPC服務(wù)

    grpcurl通過命令行訪問gRPC服務(wù)

    這篇文章主要為大家介紹了grpcurl通過命令行訪問gRPC服務(wù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Golang官方限流器time/rate的使用與實(shí)現(xiàn)詳解

    Golang官方限流器time/rate的使用與實(shí)現(xiàn)詳解

    限流器是后臺(tái)服務(wù)中十分重要的組件,在實(shí)際的業(yè)務(wù)場(chǎng)景中使用居多。time/rate?包基于令牌桶算法實(shí)現(xiàn)限流,本文主要為大家介紹了time/rate的使用與實(shí)現(xiàn),需要的可以參考一下
    2023-04-04
  • Golang使用Apache PLC4X連接modbus的示例代碼

    Golang使用Apache PLC4X連接modbus的示例代碼

    Modbus是一種串行通信協(xié)議,是Modicon公司于1979年為使用可編程邏輯控制器(PLC)通信而發(fā)表,這篇文章主要介紹了Golang使用Apache PLC4X連接modbus的示例代碼,需要的朋友可以參考下
    2024-07-07
  • Golang哈希算法實(shí)現(xiàn)配置文件的監(jiān)控功能詳解

    Golang哈希算法實(shí)現(xiàn)配置文件的監(jiān)控功能詳解

    這篇文章主要介紹了Golang哈希算法實(shí)現(xiàn)配置文件的監(jiān)控功能,哈希和加密類似,唯一區(qū)別是哈希是單項(xiàng)的,即哈希后的數(shù)據(jù)無法解密,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-03-03
  • 詳解Go程序添加遠(yuǎn)程調(diào)用tcpdump功能

    詳解Go程序添加遠(yuǎn)程調(diào)用tcpdump功能

    這篇文章主要介紹了go程序添加遠(yuǎn)程調(diào)用tcpdump功能,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-05-05
  • Go語言中多重賦值里的空白標(biāo)識(shí)符的使用

    Go語言中多重賦值里的空白標(biāo)識(shí)符的使用

    Go語言中,空白標(biāo)識(shí)符_用于多重賦值時(shí)忽略多余值,提升代碼簡(jiǎn)潔性,適用于函數(shù)返回、遍歷映射、接口斷言、數(shù)據(jù)庫查詢及通道接收等場(chǎng)景,下面就來介紹一下,感興趣的可以了解一下
    2025-06-06
  • 解決golang json解析出現(xiàn)值為空的問題

    解決golang json解析出現(xiàn)值為空的問題

    這篇文章主要介紹了解決golang json解析出現(xiàn)值為空的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12

最新評(píng)論

定边县| 台中市| 兴海县| 淮北市| 长阳| 大同市| 祁阳县| 保山市| 友谊县| 玛纳斯县| 呼伦贝尔市| 额济纳旗| 游戏| 汨罗市| 金秀| 潮州市| 常州市| 成武县| 浠水县| 陕西省| 湖南省| 鸡西市| 侯马市| 鹿泉市| 灵石县| 沙雅县| 科技| 玉树县| 桂阳县| 铁力市| 环江| 郯城县| 枞阳县| 屯门区| 南城县| 衡东县| 元氏县| 逊克县| 凌海市| 曲水县| 英吉沙县|