国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

go 語(yǔ)言中 map 的相關(guān)知識(shí)

這篇具有很好參考價(jià)值的文章主要介紹了go 語(yǔ)言中 map 的相關(guān)知識(shí)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

Go map key類型分析

1 map的key類型

map中的key可以是任何的類型,只要它的值能比較是否相等,Go的語(yǔ)言規(guī)范已精確定義,Key的類型可以是:

  • 布爾值
  • 數(shù)字
  • 字符串
  • 指針
  • 通道
  • 接口類型
  • 結(jié)構(gòu)體
  • 只包含上述類型的數(shù)組

但不能是:

  • slice
  • map
  • function

Key類型只要能支持和!=操作符,即可以做為Key,當(dāng)兩個(gè)值時(shí),則認(rèn)為是同一個(gè)Key。

2 比較相等

我們先看一下樣例代碼:

**package** main

**import** "fmt"

**type** _key **struct** {
}

**type** point **struct** {
	x **int**
	y **int**
}

**type** pair **struct** {
	x **int**
	y **int**
}

**type** Sumer **interface** {
	Sum() **int**
}

**type** Suber **interface** {
	Sub() **int**
}

**func** (p *pair) Sum() **int** {
	**return** p.x + p.y
}

**func** (p *point) Sum() **int** {
	**return** p.x + p.y
}

**func** (p pair) Sub() **int** {
	**return** p.x - p.y
}

**func** (p point) Sub() **int** {
	**return** p.x - p.y
}

**func** main() {
	fmt.Println("_key{} == _key{}: ", _key{} == _key{}) // output: true

	fmt.Println("point{} == point{}: ", point{x: 1, y: 2} == point{x: 1, y: 2})     // output: true
	fmt.Println("&point{} == &point{}: ", &point{x: 1, y: 2} == &point{x: 1, y: 2}) // output: false

	fmt.Println("[2]point{} == [2]point{}: ", 
	  [2]point{point{x: 1, y: 2}, point{x: 2, y: 3}} == [2]point{point{x: 1, y: 2}, point{x: 2, y: 3}}) //output: true

	**var** a Sumer = &pair{x: 1, y: 2}
	**var** a1 Sumer = &pair{x: 1, y: 2}
	**var** b Sumer = &point{x: 1, y: 2}
	fmt.Println("Sumer.byptr == Sumer.byptr: ", a == b)        // output: false
	fmt.Println("Sumer.sametype == Sumer.sametype: ", a == a1) // output: false

	**var** c Suber = pair{x: 1, y: 2}
	**var** d Suber = point{x: 1, y: 2}
	**var** d1 point = point{x: 1, y: 2}
	fmt.Println("Suber.byvalue == Suber.byvalue: ", c == d)  // output: false
	fmt.Println("Suber.byvalue == point.byvalue: ", d == d1) // output: true

	ci1 := make(**chan** **int**, 1)
	ci2 := ci1
	ci3 := make(**chan** **int**, 1)
	fmt.Println("chan int == chan int: ", ci1 == ci2) // output: true
	fmt.Println("chan int == chan int: ", ci1 == ci3) // output: false
}

上面的例子讓我們較直觀地了解結(jié)構(gòu)體,數(shù)組,指針,chan在什么場(chǎng)景下是相等。我們?cè)賮?lái)看Go語(yǔ)言規(guī)范中是怎么說(shuō)的:

  • Pointer values are comparable. Two pointer values are equal if they point to the same variable or if both have value nil. Pointers to distinct zero-size variables may or may not be equal.當(dāng)指針指向同一變量,或同為nil時(shí)指針相等,但指針指向不同的零值時(shí)可能不相等。
  • Channel values are comparable. Two channel values are equal if they were created by the same call to make or if both have value nil.Channel當(dāng)指向同一個(gè)make創(chuàng)建的或同為nil時(shí)才相等
  • Interface values are comparable. Two interface values are equal if they have identical dynamic types and equal dynamic values or if both have value nil.從上面的例子我們可以看出,當(dāng)接口有相同的動(dòng)態(tài)類型并且有相同的動(dòng)態(tài)值,或者值為都為nil時(shí)相等。要注意的是:參考理解Go Interface
  • A value x of non-interface type X and a value t of interface type T are comparable when values of type X are comparable and X implements T. They are equal if t’s dynamic type is identical to X and t’s dynamic value is equal to x.如果一個(gè)是非接口類型X的變量x,也實(shí)現(xiàn)了接口T,與另一個(gè)接口T的變量t,只t的動(dòng)態(tài)類型也是類型X,并且他們的動(dòng)態(tài)值相同,則他們相等。
  • Struct values are comparable if all their fields are comparable. Two struct values are equal if their corresponding non-blank fields are equal.結(jié)構(gòu)體當(dāng)所有字段的值相同,并且沒(méi)有 相應(yīng)的非空白字段時(shí),則他們相等,
  • Array values are comparable if values of the array element type are comparable. Two array values are equal if their corresponding elements are equal.兩個(gè)數(shù)組只要他們包括的元素,每個(gè)元素的值相同,則他們相等。

注意:Go語(yǔ)言里是無(wú)法重載操作符的,struct是遞歸操作每個(gè)成員變量,struct也可以稱為map的key,但如果struct的成員變量里有不能進(jìn)行==操作的,例如slice,那么就不能作為map的key。

3 類型判斷

判斷兩個(gè)變量是否相等,首先是要判斷變量的動(dòng)態(tài)類型是否相同,在runtime中,_type結(jié)構(gòu)是描述最為基礎(chǔ)的類型(runtime/type.go),而map, slice, array等內(nèi)置的復(fù)雜類型也都有對(duì)應(yīng)的類型描述(如maptype,slicetype,arraytype)。

type _type struct {
	size       uintptr
	ptrdata    uintptr 
	hash       uint32
	tflag      tflag
	align      uint8
	fieldalign uint8
	kind       uint8
	alg        *typeAlg
	gcdata    *byte
	str       nameOff
	ptrToThis typeOff
}
...
type chantype struct {
	typ  _type
	elem *_type
	dir  uintptr
}
...
type slicetype struct {
	typ  _type
	elem *_type
}
...

其中對(duì)于類型的值是否相等,需要使用到成員alg *typeAlg(runtime/alg.go),它則持有此類型值的hash與equal的算法,它也是一個(gè)結(jié)構(gòu)體:

type typeAlg struct {
	// function for hashing objects of this type
	// (ptr to object, seed) -> hash
	hash func(unsafe.Pointer, uintptr) uintptr
	// function for comparing objects of this type
	// (ptr to object A, ptr to object B) -> ==?
	equal func(unsafe.Pointer, unsafe.Pointer) bool
}

runtime/alg.go中提供了各種基礎(chǔ)的hash func與 equal func,例如:

func strhash(a unsafe.Pointer, h uintptr) uintptr {
	x := (*stringStruct)(a)
	return memhash(x.str, h, uintptr(x.len))
}

func strequal(p, q unsafe.Pointer) bool {
	return *(*string)(p) == *(*string)(q)
}

有了這些基礎(chǔ)的hash func與 equal func,再?gòu)?fù)雜的結(jié)構(gòu)體也可以按字段遞歸計(jì)算hash與相等比較了。那我們?cè)賮?lái)看一下,當(dāng)訪問(wèn)map[key]時(shí),其實(shí)現(xiàn)對(duì)應(yīng)在runtime/hashmap.go中的mapaccess1函數(shù):

func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
	...
	alg := t.key.alg
	hash := alg.hash(key, uintptr(h.hash0)) // 1
	m := uintptr(1)<<h.B - 1
	b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize))) // 2
	...
	top := uint8(hash >> (sys.PtrSize*8 - 8))
	if top < minTopHash {
		top += minTopHash
	}
	for {
		for i := uintptr(0); i < bucketCnt; i++ {
			...
			k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
			if alg.equal(key, k) { // 3
				v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
				...
				return v
			}
		}
	...
	}
}

mapaccess1的代碼還是比較多的,簡(jiǎn)化邏輯如下(參考注釋上序列):

  1. 調(diào)用key類型的hash方法,計(jì)算出key的hash值
  2. 根據(jù)hash值找到對(duì)應(yīng)的桶bucket
  3. 在桶中找到key值相等的map的value。判斷相等需調(diào)用key類型的equal方法

到現(xiàn)在我們也就有了初步了解,map中的key訪問(wèn)時(shí)同時(shí)需要使用該類型的hash func與 equal func,只要key值相等,當(dāng)結(jié)構(gòu)體即使不是同一對(duì)象,也可從map中獲取相同的值,例如:

m := make(map[interface{}]interface{})
m[_key{}] = "value"
if v, ok := m[_key{}];ok {
	fmt.Println("%v", v) // output: value
}

判斷兩個(gè) map 是否相等

比較兩個(gè)map實(shí)例需要使用reflect包的DeepEqual()方法。如果相比較的兩個(gè)map滿足以下條件,方法返回true:

Map values are deeply equal when all of the following are true: they are both nil or both non-nil, they have the same length, and either they are the same map object or their corresponding keys (matched using Go equality) map to deeply equal values.

1.兩個(gè)map都為nil或者都不為nil,并且長(zhǎng)度要相等 they are both nil or both non-nil, they have the same length 2.相同的map對(duì)象或者所有key要對(duì)應(yīng)相同 either they are the same map object or their corresponding keys 3.map對(duì)應(yīng)的value也要深度相等 map to deeply equal values

Go 為什么不在語(yǔ)言層面支持 map 并發(fā)?

為什么原生不支持

憑什么 Go 官方還不支持,難不成太復(fù)雜了,性能太差了,到底是為什么?
官方答復(fù)原因如下(via @go faq):

  • 典型使用場(chǎng)景:map 的典型使用場(chǎng)景是不需要從多個(gè) goroutine 中進(jìn)行安全訪問(wèn)。
  • 非典型場(chǎng)景(需要原子操作):map 可能是一些更大的數(shù)據(jù)結(jié)構(gòu)或已經(jīng)同步的計(jì)算的一部分。
  • 性能場(chǎng)景考慮:若是只是為少數(shù)程序增加安全性,導(dǎo)致 map 所有的操作都要處理 mutex,將會(huì)降低大多數(shù)程序的性能。

核心來(lái)講就是:Go 團(tuán)隊(duì)在經(jīng)過(guò)了長(zhǎng)時(shí)間的討論后,認(rèn)為原生 map 更應(yīng)適配典型使用場(chǎng)景。
如果為了小部分情況,將會(huì)導(dǎo)致大部分程序付出性能代價(jià),決定了不支持原生的并發(fā) map 讀寫。且在 Go1.6 起,增加了檢測(cè)機(jī)制,并發(fā)的話會(huì)導(dǎo)致異常。

為什么要崩潰

前面有提到一點(diǎn),在 Go1.6 起會(huì)進(jìn)行原生 map 的并發(fā)檢測(cè),這是一些人的 “噩夢(mèng)”。
在此有人吐槽到:“明明給我拋個(gè)錯(cuò)就好了,憑什么要讓我的 Go 進(jìn)程直接崩潰掉,分分鐘給我背個(gè) P0”。

場(chǎng)景枚舉

這里我們假設(shè)一下,如果并發(fā)讀寫 map 是以下兩種場(chǎng)景:

  1. 產(chǎn)生 panic:程序 panic -> 默認(rèn)走進(jìn) recover -> 沒(méi)有對(duì)并發(fā) map 進(jìn)行處理 -> map 存在臟數(shù)據(jù) -> 程序使用臟數(shù)據(jù) -> 產(chǎn)生**未知((影響。
  2. 產(chǎn)生 crash:程序 crash -> 直接崩潰 -> 保全數(shù)據(jù)(數(shù)據(jù)正常)-> 產(chǎn)生**明確((風(fēng)險(xiǎn)。

你會(huì)選擇哪一種方案呢?Go 官方在兩者的風(fēng)險(xiǎn)衡量中選擇了第二種。
無(wú)論是編程,還是人生。如何在隨機(jī)性中掌握確定性的部分,也是一門極大的哲學(xué)了。

let it crash

Go 官方團(tuán)隊(duì)選擇的方式是業(yè)內(nèi)經(jīng)典的 “l(fā)et it crash” 行為,很多編程語(yǔ)言中,都會(huì)將其奉行為設(shè)計(jì)哲學(xué)。
let it crash 是指工程師不必過(guò)分擔(dān)心未知的錯(cuò)誤,而去進(jìn)行面面俱到的防御性編碼。
這塊理念最經(jīng)典的就是 erlang 了。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-790957.html

到了這里,關(guān)于go 語(yǔ)言中 map 的相關(guān)知識(shí)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【Golang】go編程語(yǔ)言適合哪些項(xiàng)目開(kāi)發(fā)?

    【Golang】go編程語(yǔ)言適合哪些項(xiàng)目開(kāi)發(fā)?

    前言 在當(dāng)今數(shù)字化時(shí)代,軟件開(kāi)發(fā)已成為各行各業(yè)的核心需求之一。 而選擇適合的編程語(yǔ)言對(duì)于項(xiàng)目的成功開(kāi)發(fā)至關(guān)重要。 本文將重點(diǎn)探討Go編程語(yǔ)言適合哪些項(xiàng)目開(kāi)發(fā),以幫助讀者在選擇合適的編程語(yǔ)言時(shí)做出明智的決策。 Go 編程語(yǔ)言適合哪些項(xiàng)目開(kāi)發(fā)? Go是由Google開(kāi)發(fā)

    2024年02月04日
    瀏覽(29)
  • 【Golang】VsCode下開(kāi)發(fā)Go語(yǔ)言的環(huán)境配置(超詳細(xì)圖文詳解)

    【Golang】VsCode下開(kāi)發(fā)Go語(yǔ)言的環(huán)境配置(超詳細(xì)圖文詳解)

    ??推薦網(wǎng)站(不斷完善中):個(gè)人博客 ??個(gè)人主頁(yè):個(gè)人主頁(yè) ??相關(guān)專欄:CSDN專欄、個(gè)人專欄 ??立志賺錢,干活想躺,瞎分享的摸魚工程師一枚 ? 話說(shuō)在前,Go語(yǔ)言的編碼方式是 UTF-8 ,理論上你直接使用文本進(jìn)行編輯也是可以的,當(dāng)然為了提升我們的開(kāi)發(fā)效率我們還是需

    2024年02月07日
    瀏覽(27)
  • 【Go】Go 語(yǔ)言教程--Go 語(yǔ)言Map(集合)(十六)

    往期回顧: Go 語(yǔ)言教程–介紹(一) Go 語(yǔ)言教程–語(yǔ)言結(jié)構(gòu)(二) Go 語(yǔ)言教程–語(yǔ)言結(jié)構(gòu)(三) Go 語(yǔ)言教程–數(shù)據(jù)類型(四) Go 語(yǔ)言教程–語(yǔ)言變量(五) Go 語(yǔ)言教程–GO語(yǔ)言常量(六) Go 語(yǔ)言教程–GO語(yǔ)言運(yùn)算符(七) Go 語(yǔ)言教程–GO條件和循環(huán)語(yǔ)句(八) Go 語(yǔ)言教程

    2024年02月16日
    瀏覽(23)
  • go語(yǔ)言(八)---- map

    go語(yǔ)言(八)---- map

    map的聲明方式有以下三種。 map的使用方式 map的增刪改查 map的傳參

    2024年01月20日
    瀏覽(16)
  • Go 語(yǔ)言Map(集合)

    Map 是一種無(wú)序的鍵值對(duì)的集合。Map 最重要的一點(diǎn)是通過(guò) key 來(lái)快速檢索數(shù)據(jù),key 類似于索引,指向數(shù)據(jù)的值。 Map 是一種集合,所以我們可以像迭代數(shù)組和切片那樣迭代它。不過(guò),Map 是無(wú)序的,我們無(wú)法決定它的返回順序,這是因?yàn)?Map 是使用 hash 表來(lái)實(shí)現(xiàn)的。 定義 Map 可以

    2024年02月05日
    瀏覽(15)
  • Golang:Go語(yǔ)言結(jié)構(gòu)

    在我們開(kāi)始學(xué)習(xí) Go 編程語(yǔ)言的基礎(chǔ)構(gòu)建模塊前,讓我們先來(lái)了解 Go 語(yǔ)言最簡(jiǎn)單程序的結(jié)構(gòu)。 Go 語(yǔ)言的基礎(chǔ)組成有以下幾個(gè)部分: 包聲明 引入包 函數(shù) 變量 語(yǔ)句 表達(dá)式 注釋 接下來(lái)讓我們來(lái)看下簡(jiǎn)單的代碼,該代碼輸出了\\\"Hello World!\\\": 讓我們來(lái)看下以上程序的各個(gè)部分: 第一

    2024年02月10日
    瀏覽(21)
  • golang實(shí)現(xiàn)webgis后端開(kāi)發(fā)

    golang實(shí)現(xiàn)webgis后端開(kāi)發(fā)

    目錄 前言 二、實(shí)現(xiàn)步驟 1.postgis數(shù)據(jù)庫(kù)和model的綁定 2.將pg庫(kù)中的要素轉(zhuǎn)換為geojson (1)幾何定義 (2)將wkb解析為幾何類型 (3)定義geojson類型 (4)數(shù)據(jù)轉(zhuǎn)換 (5)數(shù)據(jù)返回 ?2.前端傳入的geojson儲(chǔ)存到數(shù)據(jù)庫(kù) 3、其他功能實(shí)現(xiàn) 總結(jié) ????????停更了接近一個(gè)月都在研究一門新語(yǔ)言gola

    2024年02月08日
    瀏覽(26)
  • Go 語(yǔ)言 map 如何順序讀???

    Go 語(yǔ)言中的 map 是一種非常強(qiáng)大的數(shù)據(jù)結(jié)構(gòu),它允許我們快速地存儲(chǔ)和檢索鍵值對(duì)。 然而,當(dāng)我們遍歷 map 時(shí),會(huì)有一個(gè)有趣的現(xiàn)象,那就是輸出的鍵值對(duì)順序是不確定的。 先看一段代碼示例: 當(dāng)我們多執(zhí)行幾次這段代碼時(shí),就會(huì)發(fā)現(xiàn),輸出的順序是不同的。 首先,Go 語(yǔ)言

    2024年02月07日
    瀏覽(22)
  • Go語(yǔ)言基礎(chǔ)之map

    Go語(yǔ)言中提供的映射關(guān)系容器為map,其內(nèi)部使用散列表(hash)實(shí)現(xiàn)。 map是一種無(wú)序的基于key-value的數(shù)據(jù)結(jié)構(gòu),Go語(yǔ)言中的map是引用類型,必須初始化才能使用。 map定義 Go語(yǔ)言中 map的定義語(yǔ)法如下: 其中, KeyType:表示鍵的類型。 ValueType:表示鍵對(duì)應(yīng)的值的類型。 map類型的變量

    2024年02月11日
    瀏覽(25)
  • Go語(yǔ)言入門5(map哈希表)

    ?哈希表是一種巧妙并且實(shí)用的數(shù)據(jù)結(jié)構(gòu)。它是一個(gè)無(wú)序的key/value對(duì)的集合,其中所有的key 都是不同的,然后通過(guò)給定的key可以在常數(shù)時(shí)間復(fù)雜度內(nèi)檢索、更新或刪除對(duì)應(yīng)的value。 ?在Go語(yǔ)言中,一個(gè)map就是一個(gè)哈希表的引用,map類型可以寫為map[K]V,其中K和V分別 對(duì)應(yīng)key和

    2023年04月11日
    瀏覽(21)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包