1. 程式人生 > >Go語言開發(三)、Go語言內置容器

Go語言開發(三)、Go語言內置容器

第一個 支持 指向 ice 美國 p值 索引 叠代 指定大小

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=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 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語言內置容器