網站首頁 編程語言 正文
前言
今天咱們來學習一下golang中的map數據類型,單純的總結一下基本語法和使用場景,也不具體深入底層。map類型是什么呢?做過PHP的,對于數組這種數據類型是一點也不陌生了。PHP中的數組分為索引數組
和關聯數組
。例如下面的代碼:
// 索引數組【數組的key是一個數字, 從0,1,2開始遞增】 $array = [1, '張三', 12]; // 關聯數組【數組的key是一個字符串,可以自定義key的名稱】 $array = ['id' => 1, 'name' => '張三', 'age' => 12];
在golang中,map是一種特殊的數據結構,是一種key對應一個value類型的結構。這種結構可以被稱為關聯數組和字典。
在golang中也有切片和數組這樣的數據類型,來存儲一組數據。
- 數組就好比PHP中的一維數組,并且長度是固定的,其中的值類型在定義數組的時候就確定好了。
- 切片是一種特殊的數組類型。長度是固定的。
// 數組,類型是int,長度是4。 array := [4]int{1, 2, 3, 4} // 切片,類型是int,長度不固定。 slice := []int{1, 2, 3, 4}
有數組和切片可以存儲一組數據,那為什么還有map這樣的類型結構呢?map類型具體是啥樣的呢?
案例
假設我們現在有這樣的一個需求,要用golang中的一種數據類型來存儲多個用戶的數據,這些數據分別用戶的ID,name,age,sex…等等字段。我們改用什么數據類型呢?
在PHP中我們可以直接下面的方式定義,操作也是非常簡單。
$userInfo = [ ['id' => 1, 'name' => '張三', 'age' => 12, 'sex' => '男'], ['id' => 2, 'name' => '趙六', 'age' => 22, 'sex' => '男'], ['id' => 3, 'name' => '李四', 'age' => 34, 'sex' => '女'], ['id' => 4, 'name' => '王麻子', 'age' => 56, 'sex' => '男'] ];
那如何在golang中實現呢,假設我們用數組和切片實現一下試試。
// 1. 用數組實現 $user1 := [4]string{"1", "張三", "12", "男"} $user2 := [4]string{"2", "趙六", "12", "男"} $user3 := [4]string{"3", "李四", "12", "女"} $user4 := [4]string{"4", "王麻子", "12", "男"} // 2. 用戶切片實現 $user1 := []string{"1", "張三", "12", "男"} $user2 := []string{"2", "趙六", "12", "男"} $user3 := []string{"3", "李四", "12", "女"} $user4 := []string{"4", "王麻子", "12", "男"}
通過上面的示例代碼,我們是不是看得出來存在這樣幾個問題:
- a. 可讀性低。我們完全不知道1、12這樣的值是用戶的什么信息,男、張三我們還可以猜測一下是名字和性別。
- b. 重復代碼。一個用戶一個變量,如果存在千萬個用戶,我們豈不是需要定義千萬個變量。
- c. 繁瑣。相比PHP的實現,是不是非常繁瑣。PHP中直接定義一個變量,通過多維數組的方式,就可以定義key和值。清晰并且簡單。這也是為什么大家都說PHP中的數組非常強大和好用了。
通過切片和數組實現的方式,我們知道了弊端。那有不有一種數據類型能夠像PHP這樣簡單就能實現呢?這樣的場景就可以用map實現PHP這樣的定義結構。接下來,我們就具體總結一下map相關的操作。
map
map定義
map 是一種特殊的數據結構:一種元素對(pair)的無序集合,pair 的一個元素是 key,對應的另一個元素是 value,所以這個結構也稱為關聯數組或字典。這是一種快速尋找值的理想結構:給定 key,對應的 value 可以迅速定位。
map 這種數據結構在其他編程語言中也稱為字典(Python)、hash 和 HashTable 等。
map聲明
map屬于一種引用類型,在使用時我們需要make給其分配內存空間,未分配內存空間的map值是一個nil。
map聲明時,需要指定key的類型和值的類型,并且復制時,必須按照定義時的類型進行復制。 map的值可以是任意類型,可以是切片可以是數組,可以是接口、結構體、指針、字符串等等數據類型。 var map1 map[key類型]值類型 // 聲明方式一,完整模式 var map1 map[int]string map1 = make(map[int]string[, n]) // 聲明方式二,段語法風格 map1 := make(map[int]string[, n])
上面的n都是map的容量,也就是說map可以存儲元素的數量。可以省略,map會動態擴容。
示例小案例,我們用map存儲一個用戶的信息。用戶信息包含ID,name,age字段。
userInfo := make(map[string]string) userInfo["id"] = "1" userInfo["name"] = "張三" userInfo["age"] = "12" fmt.Println(userInfo) // output map[id:1 name:張三 age:12]
因為用戶信息的字段和字段值有字符串和數字類型,定義好類型之后就只能傳對應類型的值,因此我們給key和value的類型都定義為string類型。
map的操作
這里的操作,我們接著上面的小案例來使用。
- 訪問和復制。我們直接使用下標就可以了。
// 賦值 mapName[key] = "值" userInfo["name"] = "王五" // 訪問 mapName[key] name := userInfo["name"]
- 刪除元素。刪除操作,需要使用到delete(),給該函數傳遞要刪除的key。
delete(mapName, key) delete(userInfo, "name")
- 判斷某一個值key是否存在。上面我們訪問map中的key,直接使用下標就可以了。如果 map 中不存在 key1,val1 就是一個值類型的空值。會導致我們沒法區分到底是 key不存在還是它對應的value就是空值。
value, boolean := mapName[key] // 如果boolean是一個true則說明,對應的key存在,如果是false,則說明該key不存在。 if value, ok := userInfo["address"]; !ok { fmt.Println("address key not found!") } //因為address這個key不存在,因此會輸出“address key not found!”。
- 循環。循環map,我們一般是用到?
for range
來實現。
// 語法 for value, key := range mapName { fmt.Println(key, "=>", value) } // 示例 for value, key := range userInfo { fmt.Println(key, "=>", value) } // output 1 => id 張三 => name 12 => age
總結
其實對map基本的操作就是這么簡單。對它的理解也是這么簡單。在日常開發中,我們也經常使用該類型。
回到最上面多個用戶的案例,這時候我們是不是就知道怎么使用map實現了。
- 因為是多個用戶,我們是不是需要定義多維的map結構。
- map的一級key是int,表示當前的用戶序號(從0,1,2,3…依次遞增)。key對應的值,才是某一個用戶的具體信息,我們同樣的定義map類型來存儲,key和value都是字符串,結構就像map聲明中的小案例一樣。
- 因為我們不知道用戶的具體個數,我們將一級的key定義為切片。因為切片的長度是不固定的。
userInfo := make([]map[string]string, 3) for i := 0; i < 3; i++ { userInfo[i] = make(map[string]string, 3) userInfo[i]["id"] = "ID" userInfo[i]["name"] = "名稱" userInfo[i]["age"] = "年齡" } fmt.Println(userInfo) // output [ map[id:ID name:名稱 age:年齡] map[id:ID name:名稱 age:年齡] map[id:ID name:名稱 age:年齡] ]
為什么要兩次make,因為切片和map在golang中都是引用類型。第一次在make時,是針對切片初始化內存空間,第二次是針對切片的key對應的元素分配內存空間。大致的結構就像下圖一樣。
原文鏈接:https://blog.51cto.com/u_10992108/4652560
相關推薦
- 2022-06-01 Snort中pcre和正則表達式的使用詳解_正則表達式
- 2022-08-16 Oracle數據庫事務的開啟與結束詳解_oracle
- 2024-03-28 存儲過程整合springboot
- 2022-12-19 教你react中如何理解usestate、useEffect副作用、useRef標識和useCont
- 2022-09-23 Go語言結構體Go?range的學習教程_Golang
- 2022-05-29 .NET?Core通過dotnet?publish命令發布應用_實用技巧
- 2022-12-08 C語言實現計算圓周長以及面積_C 語言
- 2022-08-16 C#?泛型List排序的實現_C#教程
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支