標籤:com 一點 定義 執行個體 大小 \n shadow 引用 技術
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 mainimport "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 mainimport "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 mainimport "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=3
s := arr[:]
使用數組arr的引用初始化切片s
s := arr[startIndex:endIndex]
將arr中從下標startIndex到endIndex-1下的元素建立為一個新的切片
s := arr[startIndex:]
預設endIndex時將表示一直到arr的最後一個元素
s := arr[:endIndex]
預設startIndex時將表示從arr的第一個元素開始
s1 := s[startIndex:endIndex]
通過切片s初始化切片s1
s :=make([]int,len,cap)
通過內建函數make()初始化切片s,[]int標識為其元素類型為int的切片
3、切片操作
切片是可索引的,並且可以由len()方法擷取長度。
切片提供了計算容量的方法cap()可以測量切片最長可以達到多少。
package mainimport "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 mainimport "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 mainimport "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 mainimport "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 mainimport "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語言Map1、Go語言Map簡介
Ma是一種無序的索引值對的集合。Map最重要的一點是通過key來快速檢索資料。
Map是一種集合,可以對其進行迭代。Map使用hash表來實現,Map是無序的,無法決定返回順序。
2、Go語言Map定義
可以使用內建函數make,也可以使用map關鍵字來定義Map:
//聲明變數,預設map是nilvar 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==nilcountryCapitalMap = 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 mainimport "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語言range1、range簡介
Go語言中range關鍵字用於for迴圈中迭代數組(array)、切片(slice)、通道(channel)或集合(map)的元素。在數組和切片中,range返回元素的索引和索引對應的值,在集合中返回key-value對的key值。
2、rang使用執行個體
package mainimport "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語言內建容器