Go語言開發(三)、Go語言內置容器
一、Go語言數組
1、Go語言數組簡介
Go語言提供了數組類型的數據結構。
數組是具有相同唯一類型的一組已編號且長度固定的數據項序列,類型可以是任意的原始類型例如×××、字符串或者自定義類型。
相對於去聲明number0, number1, ..., and number99的變量,使用數組形式numbers[0], numbers[1] ..., numbers[99]更加方便且易於擴展。
數組元素可以通過索引(位置)來讀取(或者修改),索引從0開始,第一個元素索引為 0,第二個索引為 1,以此類推。
2、Go語言數組聲明
Go 語言數組聲明需要指定元素類型及元素個數,語法格式如下:
var variable_name [SIZE] variable_type
以上為一維數組的定義方式。數組長度必須是整數且大於0。例如以下定義了數組balance長度為10類型為float32:
var balance [10] float32
3、Go語言數組初始化
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
初始化數組中{}中的元素個數不能大於[]中的數字。
如果忽略[]中的數字不設置數組大小,Go語言會根據元素的個數來設置數組的大小:var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
該實例與上面的實例是一樣的,雖然沒有設置數組的大小。
balance[4] = 50.0
以上實例讀取了第五個元素。數組元素可以通過索引(位置)來讀取(或者修改),索引從0開始,第一個元素索引為0,第二個索引為1,以此類推。
4、Go數組元素訪問
數組元素可以通過索引(位置)來讀取。格式為數組名後加中括號,中括號中為索引的值。例如:var salary float32 = balance[9]
以上實例讀取了數組balance第10個元素的值。
以下演示了數組完整操作(聲明、賦值、訪問)的實例:
package main import "fmt" func main() { var n [10]int /* n 是一個長度為 10 的數組 */ var i,j int /* 為數組 n 初始化元素 */ for i = 0; i < 10; i++ { n[i] = i + 100 /* 設置元素為 i + 100 */ } /* 輸出每個數組元素的值 */ for j = 0; j < 10; j++ { fmt.Printf("Element[%d] = %d\n", j, n[j] ) } }
5、Go語言多維數組簡介
Go 語言支持多維數組,以下為常用的多維數組聲明方式:var variable_name [SIZE1][SIZE2]...[SIZEN] variable_type
以下實例聲明了三維的整型數組:var threedim [5][10][4]int
6、Go語言二維數組聲明
二維數組是最簡單的多維數組,二維數組本質上是由一維數組組成的。二維數組定義方式如下:var arrayName [ x ][ y ] variable_type
variable_type為Go語言的數據類型,arrayName為數組名,二維數組可認為是一個表格,x為行,y為列,下圖演示了一個二維數組a為三行四列:
二維數組中的元素可通過a[ i ][ j ]來訪問。
初始化二維數組
多維數組可通過大括號來初始值。以下實例為一個3行4列的二維數組:
a = [3][4]int{
{0, 1, 2, 3} , /* 第一行索引為 0 */
{4, 5, 6, 7} , /* 第二行索引為 1 */
{8, 9, 10, 11} /* 第三行索引為 2 */
}
訪問二維數組
二維數組通過指定坐標來訪問。如數組中的行索引與列索引,例如:int val = a[2][3]
二維數組可以使用循環嵌套來輸出元素:
package main
import "fmt"
func main() {
/* 數組 - 5 行 2 列*/
var a = [5][2]int{ {0,0}, {1,2}, {2,4}, {3,6},{4,8}}
var i, j int
/* 輸出數組元素 */
for i = 0; i < 5; i++ {
for j = 0; j < 2; j++ {
fmt.Printf("a[%d][%d] = %d\n", i,j, a[i][j] )
}
}
}
7、數組參數傳遞
如果向函數傳遞數組參數,需要在函數定義時,聲明形參為數組。數組參數傳遞為值傳遞,如果要在函數內部修改數組的元素的值,需要傳遞數組指針。通常,函數的數組參數的聲明有兩種方式:
A、形參指定數組大小
func sum(arr [5] int, size int) int{
var c int = 0
var i int
for i = 0; i < size;i++{
c += arr[i]
}
return c
}
B、形參不指定數組大小
func getAverage(arr []int,size int) float32 {
var i int
var avg float32
var sum int
for i = 0; i < size; i++{
sum += arr[i]
}
avg = float32(sum / size)
return avg;
}
數組使用實例:
package main
import "fmt"
func getAverage(arr []int,size int) float32 {
var i int
var avg float32
var sum int
for i = 0; i < size; i++{
sum += arr[i]
}
avg = float32(sum / size)
return avg;
}
func sum(arr [5] int, size int) int{
var c int = 0
var i int
for i = 0; i < size;i++{
c += arr[i]
}
return c
}
func main() {
var a [] int
a = []int{1,2,6,90}
var c float32
c = getAverage(a,4)
fmt.Println(c)
var b [5] int
b = [5]int{1,2,3,4,5}
var d int = sum(b,5)
fmt.Println(d)
}
二、Go語言切片
1、切片定義
Go語言切片是對數組的抽象。
由於Go數組的長度不可改變,Go中提供了一種靈活、功能強悍的內置類型切片("動態數組"),切片的長度是不固定的,可以追加元素,在追加時可能使切片的容量增大。
可以聲明一個未指定大小的數組來定義切片:var identifier []type
使用make()函數來創建切片:var slice1 []type = make([]type, len)
可以指定容量,其中capacity為可選參數。make([]T, length, capacity)
len是數組的長度並且也是切片的初始長度。
2、切片初始化
s :=[] int {1,2,3 }
直接初始化切片,[]表示是切片類型,{1,2,3}初始化值依次是1,2,3,cap=len=3s := arr[:]
使用數組arr的引用初始化切片ss := arr[startIndex:endIndex]
將arr中從下標startIndex到endIndex-1下的元素創建為一個新的切片s := arr[startIndex:]
缺省endIndex時將表示一直到arr的最後一個元素s := arr[:endIndex]
缺省startIndex時將表示從arr的第一個元素開始s1 := s[startIndex:endIndex]
通過切片s初始化切片s1s :=make([]int,len,cap)
通過內置函數make()初始化切片s,[]int標識為其元素類型為int的切片
3、切片操作
切片是可索引的,並且可以由len()方法獲取長度。
切片提供了計算容量的方法cap()可以測量切片最長可以達到多少。
package main
import "fmt"
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
func main() {
var slice1 [] int
var slice2 [] int = make([]int, 6)
slice1 = []int{1,2,3,4}
slice2 = []int{1,2,3}
printSlice(slice1)
printSlice(slice2)
s :=[] int {1,2,3 }
fmt.Println(s)
}
4、nil切片
切片在未初始化前默認為nil,長度為0。
package main
import "fmt"
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
func main() {
var slice1 [] int
printSlice(slice1)
if slice1 == nil{
fmt.Println("slice1 is nil")
}
}
5、切片截取
可以通過設置下限及上限來設置截取切片[lower-bound:upper-bound]。
package main
import "fmt"
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
func main() {
//創建切片
numbers := []int{0,1,2,3,4,5,6,7,8}
printSlice(numbers)
//打印原始切片
fmt.Println("numbers ==", numbers)
//打印子切片從索引1(包含) 到索引4(不包含)
fmt.Println("numbers[1:4] ==", numbers[1:4])
//默認下限為0
fmt.Println("numbers[:3] ==", numbers[:3])
//默認上限為 len(s)
fmt.Println("numbers[4:] ==", numbers[4:])
numbers1 := make([]int,0,5)
printSlice(numbers1)
//打印子切片從索引0(包含)到索引2(不包含)
number2 := numbers[:2]
printSlice(number2)
//打印子切片從索引2(包含)到索引5(不包含)
number3 := numbers[2:5]
printSlice(number3)
}
6、切片的本質
切片在本質上是數組的視圖。切片是一個數組片段的描述,包含了指向數組的指針、片段的長度和容量(片段的最大長度)。切片與底層數組的關系如下:
切片的內部實現如下:
切片內部包含一個指向底層數組的某個位置的指針、切片長度信息、切片容量信息。
slice可以向後擴展,不可以向前擴展。
s[i]方式對切片數據進行引用不可以超越len(s),向後擴展不可以超越底層數組cap(s)。
package main
import "fmt"
func sliceExtend(){
//定義數組
arr := [...]int{0,1,2,3,4,5,6,7}
s1 := arr[2:6]
s2 := s1[3:5]
s3 := arr[2:]
s4 := arr[:6]
s5 := arr[:]
printSlice(s1)//len=4 cap=8 slice=[2 3 4 5]
printSlice(s2)//len=2 cap=5 slice=[5 6]
printSlice(s3)//len=8 cap=8 slice=[2 3 4 5 6 7]
printSlice(s4)//len=6 cap=10 slice=[0 1 2 3 4 5]
printSlice(s5)//len=10 cap=10 slice=[0 1 2 3 4 5 6 7]
//對切片中數據進行修改,底層數組數據也被修改
s1[0] = 100
printSlice(s1)//len=4 cap=8 slice=[100 3 4 5]
printSlice(s5)//len=10 cap=10 slice=[0 1 100 3 4 5 6 7]
fmt.Println(arr)//[0 1 100 3 4 5 6 7]
s1 = s1[2:6]
printSlice(s1)//len=4 cap=6 slice=[4 5 6 7]
//切片不能引用底層數組範圍外的數據
//printSlice(s1[2:9])//報錯
}
func main() {
sliceExtend()
}
7、切片追加和拷貝
如果想增加切片的容量,必須創建一個新的更大的切片並把原分片的內容都拷貝過來。
append()函數可以相一個切片追加一個或多個元素。
copy(dest,src)函數可以將dest切片拷貝到src切片。
追加元素時,如果切片超越了cap,系統會為切片分配一個更大的底層數組,每次需要重新分配底層數組時,底層數組的容量會翻倍增長。
package main
import "fmt"
func sliceOperate() {
var numbers = [3]int{0,1}//數組
s1 := numbers[1:]//切片
s1[0] = 101//修改切片的元素的值
printSlice(s1)//len=2 cap=2 slice=[101 0]
fmt.Println(numbers)//[0 101 0]
//向切片追加一個元素
s1 = append(s1, 2)
printSlice(s1)//len=3 cap=4 slice=[101 0 2]
//向切片添加一個元素,已經超越cap,系統會為切片分配更大的底層數組
s1 = append(s1, 3)
printSlice(s1)//len=4 cap=4 slice=[101 0 2 3]
fmt.Println(numbers)//[0 101 0]
//同時添加多個元素,系統為切片分配新的底層數組
s1 = append(s1, 4,5,6)
printSlice(s1)//len=7 cap=8 slice=[101 0 2 3 4 5 6]
fmt.Println(numbers)//[0 101 0]
//創建切片numbers1,len與numbers切片相同,cap為2倍
s2 := make([]int, len(s1), (cap(s1))*2)
//拷貝numbers的內容到numbers1
copy(s2,s1)
printSlice(s2)//len=7 cap=16 slice=[101 0 2 3 4 5 6]
//將s2中的0刪除
s2 = append(s2[0:1], s2[2:]...)
printSlice(s2)//len=6 cap=16 slice=[101 2 3 4 5 6]
//刪除第一個元素
front := s2[0]
fmt.Println(front)//101
s3 := s2[1:]
printSlice(s3)//len=5 cap=15 slice=[2 3 4 5 6]
//刪除最後一個元素
tail := s2[len(s2)-1]
s4 := s2[:len(s2) - 1]
fmt.Println(tail)//6
printSlice(s4)//len=5 cap=16 slice=[101 2 3 4 5]
}
func main() {
sliceOperate()
}
三、Go語言Map
1、Go語言Map簡介
Ma是一種無序的鍵值對的集合。Map最重要的一點是通過key來快速檢索數據。
Map是一種集合,可以對其進行叠代。Map使用hash表來實現,Map是無序的,無法決定返回順序。
2、Go語言Map定義
可以使用內建函數make,也可以使用map關鍵字來定義Map:
//聲明變量,默認map是nil
var map_variable map[key_data_type]value_data_type
//使用make函數
map_variable := make(map[key_data_type]value_data_type)
如果不初始化map,會創建一個nil的map。nil的map不能用來存放鍵值對。
//map集合創建
var countryCapitalMap map[string]string//countryCapitalMap==nil
countryCapitalMap = make(map[string]string)//countryCapitalMap == empty map
3、Go語言Map操作
獲取元素:map[key]
key不存在時,獲得value類型的初始值。
用value,ok := map[key]來判斷是否存在key。
使用range遍歷key,遍歷key,value對,遍歷不保證順序。
使用len獲得map的元素個數.
map使用哈希表,必須可以比較相等。
除了slice、map、function的內置類型都可以作為key。struct類型如果不包含slice、map、func字段可以作為key。
delete()函數用於刪除集合的元素, 參數為map和其對應的key。
package main
import "fmt"
func mapDemo(){
//map集合創建
var countryCapitalMap map[string]string
countryCapitalMap = make(map[string]string)
//map插入key-value對
countryCapitalMap["France"] = "Paris"
countryCapitalMap["Italy"] = "羅馬"
countryCapitalMap["Japan"] = "東京"
countryCapitalMap["India"] = "新德裏"
//map值的修改
countryCapitalMap["France"] = "巴黎"
//輸出國家首都信息
for country := range countryCapitalMap {
fmt.Println(country, "首都是", countryCapitalMap [country])
}
//查看元素在集合中是否存在
captial, ok := countryCapitalMap["美國"]
//如果確定是真實的,則存在,否則不存在
if (ok) {
fmt.Println("美國的首都是", captial)
} else {
fmt.Println("美國的首都不存在")
}
}
func deleteMap(){
//創建map
countryCapitalMap := map[string]string{"France": "Paris", "Italy": "Rome", "Japan": "Tokyo", "India": "New delhi"}
fmt.Println("原始地圖")
//打印地圖
for country := range countryCapitalMap {
fmt.Println(country, "首都是", countryCapitalMap [ country ])
}
//刪除元素
delete(countryCapitalMap, "France")
fmt.Println("法國條目被刪除")
fmt.Println("刪除元素後地圖")
//打印地圖
for country := range countryCapitalMap {
fmt.Println(country, "首都是", countryCapitalMap [ country ])
}
}
func main() {
mapDemo()
deleteMap()
}
四、Go語言range
1、range簡介
Go語言中range關鍵字用於for循環中叠代數組(array)、切片(slice)、通道(channel)或集合(map)的元素。在數組和切片中,range返回元素的索引和索引對應的值,在集合中返回key-value對的key值。
2、rang使用實例
package main
import "fmt"
func rangeDemo(){
//使用range遍歷切片
nums := []int{2, 3, 4}
sum := 0
//返回的切片的索引可以省略
for _, num := range nums {
sum += num
}
fmt.Println("sum:", sum)
//在切片上使用range,返回index和值
for i, num := range nums {
if num == 3 {
fmt.Println("index:", i)
}
}
fmt.Println(sum)
//使用range叠代map
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
fmt.Printf("%s -> %s\n", k, v)
}
//使用range遍歷Unicode字符串,返回字符的索引與字符(Unicode的值)本身
for i, c := range "go" {
fmt.Println(i, c)
}
}
func main() {
rangeDemo()
a := map[int]string{1:"hello",2:"world"}
for k,v := range a{
fmt.Println(k,v)
}
}
Go語言開發(三)、Go語言內置容器