欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Go語言中自定義結(jié)構(gòu)體能作為map的key嗎

 更新時間:2023年06月06日 11:49:23   作者:starrySky  
在Go中,引用類型具有動態(tài)的特性,可能會被修改或指向新的數(shù)據(jù),這就引發(fā)了一個問題—能否將包含引用類型的自定義結(jié)構(gòu)體作為map的鍵呢,本文就來和大家想想講講

1. 引言

在 Go 語言中,map是一種內(nèi)置的數(shù)據(jù)類型,它提供了一種高效的方式來存儲和檢索數(shù)據(jù)。map是一種無序的鍵值對集合,其中每個鍵與一個值相關(guān)聯(lián)。使用 map 數(shù)據(jù)結(jié)構(gòu)可以快速地根據(jù)鍵找到對應(yīng)的值,而無需遍歷整個集合。

在 Go 語言中,map 是一種內(nèi)置的數(shù)據(jù)類型,可以通過以下方式聲明和初始化:

m := make(map[keyType]valueType)

在使用map時,我們通常會使用基本數(shù)據(jù)類型作為鍵。然而,當我們需要將自定義的結(jié)構(gòu)體作為鍵時,就需要考慮結(jié)構(gòu)體中是否包含引用類型的字段。引用類型是指存儲了數(shù)據(jù)的地址的類型,如指針、切片、字典和通道等。在Go中,引用類型具有動態(tài)的特性,可能會被修改或指向新的數(shù)據(jù)。這就引發(fā)了一個問題:能否將包含引用類型的自定義結(jié)構(gòu)體作為map的鍵呢?

2. map的基本模型

了解能否將包含引用類型的自定義結(jié)構(gòu)體作為map的鍵這個問題,我們需要先了解下map的基本模型。在Go語言中,map是使用哈希表實現(xiàn)的。哈希表是一種以鍵-值對形式存儲數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu),它通過使用哈希函數(shù)將鍵映射到哈希值。

哈希函數(shù)是用于將鍵映射到哈希值的算法。它接受鍵作為輸入并生成一個固定長度的哈希值。Go語言的 map 使用了內(nèi)部的哈希函數(shù)來計算鍵的哈希值。

而不同的key通過哈希函數(shù)生成的哈希值可能是相同的,此時便發(fā)生了哈希沖突。哈希沖突指的是不同的鍵經(jīng)過哈希函數(shù)計算后得到相同的哈希值。由于哈希函數(shù)的輸出空間遠遠小于鍵的輸入空間,哈希沖突是不可避免的。此時無法判斷該key是當前哈希表中原本便已經(jīng)存在的元素還是由于哈希沖突導(dǎo)致不同的鍵映射到同一個bucket。 此時便需要判斷這兩個key是否相等。

因此,在map中,作為map中的key,需要保證其支持對比操作的,能夠比較兩個key是否相等。

3. map 鍵的要求

從上面map基本的模型介紹中,我們了解到,map中的Key需要支持哈希函數(shù)的計算,同時鍵的類型必須支持對比操作。

map中,計算key的哈希值,是由默認哈希函數(shù)實現(xiàn)的,對于map中的key并沒有額外的要求。

map中,判斷兩個鍵是否相等是通過調(diào)用鍵類型的相等運算符(==!=)來完成的,因此key必須確保該類型支持 == 操作。這個要求是由 map 的實現(xiàn)機制決定的。map 內(nèi)部使用鍵的相等性來確定鍵的存儲位置和檢索值。如果鍵的類型不可比較,就無法進行相等性比較,從而導(dǎo)致無法準確地定位鍵和檢索值。

在 Go 中,基本數(shù)據(jù)類型(如整數(shù)、浮點數(shù)、字符串)和一些內(nèi)置類型都是可比較的,因此它們可以直接用作 map 的鍵。然而,自定義的結(jié)構(gòu)體作為鍵時,需要確保結(jié)構(gòu)體的所有字段都是可比較的類型。如果結(jié)構(gòu)體包含引用類型的字段,那么該結(jié)構(gòu)體就不能直接用作 map 的鍵,因為引用類型不具備簡單的相等性比較。

因此,假如map中的鍵為自定義類型,同時包含引用字段,此時將無法作為map的鍵,會直接編譯失敗,代碼示例如下:

type Person struct {
   Name    string
   Age     int
   address []Address
}
func main() {
    // 這里會直接編譯不通過
    m := make(map[Person]int)
}

其次還有一個例外,那便是自定義結(jié)構(gòu)體中包含指針類型的字段,此時其是支持==操作的,但是其是使用指針地址來進行hash計算以及相等性比較的,有可能我們理解是同一個key,事實上從map來看并不是,此時非常容易導(dǎo)致錯誤,示例如下:

type Person struct {
   Name    string
   Age     int
   address *Address
}
func main(){
    m := make(map[Person]int)
    p1 := Person{Name: "Alice", Age: 30, address: &Address{city: "beijing"}}
    p2 := Person{Name: "Alice", Age: 30, address: &Address{city: "beijing"}}
    m[p1] = 1
    m[p2] = 2
    // 輸出1
    fmt.Println(m[p1])
    // 輸出2
    fmt.Println(m[p2])
}

這里我們定義了一個Person結(jié)構(gòu)體,包含一個指針類型的字段address。創(chuàng)建了兩個對象p1p2,在我們的理解中,其是同一個對象,事實上在map中為兩個兩個互不相關(guān)的對象,主要原因都是使用地址來進行hash計算以及相等性比較的。

綜上所述,如果自定義結(jié)構(gòu)體中包含引用類型的字段(指針為特殊的引用類型),此時將不能作為map類型的key。

4. 為什么不抽取hashCode和equals方法接口,由用戶自行實現(xiàn)呢

當前gomap中哈希值的計算,其提供了默認的哈希函數(shù),不需要由用戶去實現(xiàn);其次key的相等性比較,是通過== 操作符來實現(xiàn)的,也不由用戶自定義比較函數(shù)。那我們就有一個疑問了,為什么不抽取hashCode和equals方法接口,由用戶來實現(xiàn)呢?

4.1 簡單性和性能角度

相等性比較在 Go 語言中使用 == 操作符來實現(xiàn),而哈希函數(shù)是由運行時庫提供的默認實現(xiàn)。這種設(shè)計選擇我理解可能基于以下幾個原因:

  • 簡單性:對于默認哈希函數(shù)函數(shù)來說,其內(nèi)置在語言中的,無需用戶額外的實現(xiàn)和配置。這簡化了 map 的使用。對于相等性比較操作,== 操作符進行比較是一種直觀且簡單的方式。在語法上,== 操作符用于比較兩個值是否相等,這種語法的簡潔性使得代碼更易讀和理解。
  • 性能:默認的哈希函數(shù)是經(jīng)過優(yōu)化和測試的,能夠在大多數(shù)情況下提供良好的性能。其次使用==來實現(xiàn)相等性比較,由于 == 操作符是語言層面的原生操作,編譯器可以對其進行優(yōu)化,從而提高代碼的執(zhí)行效率。

4.2 key不可變的限制

map鍵的不可變性也是一個考慮因素。基于==來判斷對象是否相等,間接保證了鍵的不可變性。目前,==已經(jīng)支持了大部分類型的比較,只有自定義結(jié)構(gòu)體中的引用類型字段無法直接使用==進行比較。如果鍵中不存在引用類型字段,這意味著放入Map鍵的值在運行時不能發(fā)生變化,從而保證了鍵在運行時的不可變性。

如果key沒有不可變的限制,那么之前存儲在 map 中的鍵值對可能會出現(xiàn)問題。因為在放置元素時,map 會根據(jù)鍵的當前值計算哈希值,并使用哈希值來查找對應(yīng)的存儲位置。如果放在map中的鍵的值發(fā)生了變化,此時計算出來的hash值可能也發(fā)生變化,這意味數(shù)據(jù)放在了錯誤的位置。后續(xù)即使使用跟map中的鍵的同一個值去查找數(shù)據(jù),也可能查找不到數(shù)據(jù)。

下面展示一個簡單的代碼,來說明可變類型作為key會導(dǎo)致的問題:

type Person struct {
    Name       string
    Age        int
    SliceField []string
}
func main() {
    person := Person{Name: "Alice", Age: 25, SliceField: []string{"A", "B"}}
    // 假設(shè)Person可以作為鍵,事實上是不支持的
    personMap := make(map[Person]string)
    personMap[person] = "Value 1"
    // 修改person中SliceField的值
    person.SliceField[0] = "X"
    // 嘗試通過相同的person查找值
    fmt.Println(personMap[person]) // 輸出空字符串,找不到對應(yīng)的值
}

如果抽取equals方法接口,由用戶自行實現(xiàn),此時key的不可變性就需要用戶實現(xiàn),其次go語言也需要增加一些檢測機制,這首先增加了用戶使用的負擔,這并不符合go語言設(shè)計的哲學(xué)。

4.3 總結(jié)

綜上所述,基于簡單性、性能和語義一致性的考慮以及鍵的不可變性,Go語言選擇使用==操作符進行鍵的比較,而將哈希函數(shù)作為運行時庫的默認實現(xiàn),更加符合go語言設(shè)計的哲學(xué)。

5. 總結(jié)

在 Go 語言中,map 是一種無序的鍵值對集合,它提供了高效的數(shù)據(jù)存儲和檢索機制。在使用 map 時,通常使用基本數(shù)據(jù)類型作為鍵。然而,當我們想要使用自定義結(jié)構(gòu)體作為鍵時,需要考慮結(jié)構(gòu)體中是否包含引用類型的字段。

自定義結(jié)構(gòu)體作為map的鍵需要滿足一些要求。首先,鍵的類型必須是可比較的,也就是支持通過== 運算符進行相等性比較。在Go中,基本數(shù)據(jù)類型和一些內(nèi)置類型都滿足這個要求。但是,如果結(jié)構(gòu)體中包含引用類型的字段,那么該結(jié)構(gòu)體就不能直接作為map的鍵,因為引用類型不具備簡單的相等性比較。

因此總的來說,包含引用類型字段的自定義結(jié)構(gòu)體,是不能作為mapkey的。

以上就是詳解Go語言中自定義結(jié)構(gòu)體能作為map的key嗎的詳細內(nèi)容,更多關(guān)于Go語言map的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Golang中設(shè)置全局變量并在其他文件中使用

    Golang中設(shè)置全局變量并在其他文件中使用

    全局變量是被整個程序都可見的變量,通常用于存儲程序中需要共享的數(shù)據(jù),本文就來介紹一下Golang中設(shè)置全局變量并在其他文件中使用的方法,感興趣的可以了解一下
    2024-01-01
  • Kafka安裝部署+go整合過程

    Kafka安裝部署+go整合過程

    go語言是一種快速、分布式、并發(fā)編程的語言,它天生適合于處理高并發(fā)場景下的消息傳遞和處理,在本文中,我們將介紹Kafka安裝部署+go整合過程,感興趣的朋友一起看看吧
    2024-08-08
  • Go語言如何實現(xiàn)TCP通信詳解

    Go語言如何實現(xiàn)TCP通信詳解

    go里面實現(xiàn)tcp沒有像之前寫的C++那些那么麻煩,在C++里面要先創(chuàng)建套接字,然后綁定ip地址,go里面直接就一個函數(shù)建立套接字,然后在進行通信就可以了,下面這篇文章主要給大家介紹了關(guān)于Go語言如何實現(xiàn)TCP通信的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • 如何用go-zero 實現(xiàn)中臺系統(tǒng)

    如何用go-zero 實現(xiàn)中臺系統(tǒng)

    這篇文章主要介紹了如何用go-zero 實現(xiàn)中臺系統(tǒng),本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • 淺析Go匯編語法和MatrixOne使用介紹

    淺析Go匯編語法和MatrixOne使用介紹

    MatrixOne由Go語言所開發(fā)是一個新一代超融合異構(gòu)數(shù)據(jù)庫,致力于打造單一架構(gòu)處理TP、AP、流計算等多種負載的極簡大數(shù)據(jù)引擎,今天通過本文給大家介紹Go匯編語法和MatrixOne使用,感興趣的朋友一起看看吧
    2022-04-04
  • 使用Go語言中的Context取消協(xié)程執(zhí)行的操作代碼

    使用Go語言中的Context取消協(xié)程執(zhí)行的操作代碼

    在 Go 語言中,協(xié)程(goroutine)是一種輕量級的線程,非常適合處理并發(fā)任務(wù),然而,如何優(yōu)雅地取消正在運行的協(xié)程是一個常見的問題,本文將通過一個具體的例子來展示如何使用 context 包來取消協(xié)程的執(zhí)行,需要的朋友可以參考下
    2024-11-11
  • gin?session中間件使用及源碼流程分析

    gin?session中間件使用及源碼流程分析

    這篇文章主要為大家介紹了gin?session中間件使用及源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • Go語言學(xué)習(xí)之將mp4通過rtmp推送流媒體服務(wù)的實現(xiàn)方法

    Go語言學(xué)習(xí)之將mp4通過rtmp推送流媒體服務(wù)的實現(xiàn)方法

    對音視頻一直是小白,決定沉下心來,好好研究一下音視頻知識,下面這篇文章主要給大家介紹了關(guān)于Go語言學(xué)習(xí)之將mp4通過rtmp推送流媒體服務(wù)的實現(xiàn)方法,需要的朋友可以參考下
    2022-12-12
  • Go語言通過http抓取網(wǎng)頁的方法

    Go語言通過http抓取網(wǎng)頁的方法

    這篇文章主要介紹了Go語言通過http抓取網(wǎng)頁的方法,實例分析了Go語言通過http操作頁面的技巧,需要的朋友可以參考下
    2015-03-03
  • Go并發(fā)編程實現(xiàn)數(shù)據(jù)競爭

    Go并發(fā)編程實現(xiàn)數(shù)據(jù)競爭

    本文主要介紹了Go并發(fā)編程實現(xiàn)數(shù)據(jù)競爭,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09

最新評論