1. 程式人生 > >GO語言學習(三):指標,切片,map對映

GO語言學習(三):指標,切片,map對映

1.指標

func main() {
    var a int = 10
    //每個變數有2層含義,變數的記憶體,變數的地址
    fmt.Printf("a =%d\n", a)
    fmt.Printf("&a =%v\n", &a)

    //儲存某個變數的地址,需要指標型別,
    //*int儲存int的地址,**int儲存*int的地址
    var p *int
    //宣告(定義),定義只是特殊的宣告
    p = &a //指標變數指向誰,就把誰的地址賦值給指標變數
    fmt.Printf("p =%v, &a =%v\n", p, &a)

    *p =666 //*p操作的不是記憶體,是p所指向的記憶體(就是a)
    fmt.Printf("p =%v, a =%v\n", *p, a)  //666  666
}

go語言雖然保留指標,但與其它程式語言不同的是
1)預設值是nil,沒有NULL常量
2)操作符"&“是取變數地址,”*“通過指標訪問目標物件
3)不支援指標運算,不支援 “->” 運算子,直接用”."訪問目標成員
go語言指標定義

func main() {
   var p *int
   p = new(int) //new一個新空間,go語言不需要釋放
   q := new(int)
}

指標交換a,b值

func swap(a, b *int){
    *a, *b = *b, *a
    fmt.Printf("swap: a = %d, b =%d\n", a, b)
}
func main() {
    a, b := 10, 20

    //通過一個函式交換a和b的內容
    swap(&a, &b) //變數本身傳遞,值傳遞(站在變數角度)
    fmt.Printf("main: a = %d, b =%d\n", a, b)
}

一維陣列賦值

func main() {
    //宣告定義同時賦值,叫初始化
    //1.全部初始化
    var a [5]int = [5]int{1, 2, 3, 4, 5}
    fmt.Println("a =", a)

    b := [5]int{1,2,3,4,5}
    fmt.Println("b =", b)

    //部分初始化,沒有初始化的元素自動賦值為0
    c := [5]int{1,2,3}
    fmt.Println("c =", c)

    //指定某個元素初始化
    d := [5]int{2:10, 4:10}
    fmt.Println("d =", d)
}

二維陣列賦值

func main() {

    //二維陣列初始化,可部分初始化,沒有初始化的值為0
    e := [3][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 20, 32, 53}}
    fmt.Println(e)

    //部分初始化,只對第二行元素賦值
    f := [3][4]int{1: {5, 6, 7, 8}}
    fmt.Println(f)
}

兩陣列間支援比較和賦值,只支援 == 或 !=,比較是不是每個元素都一樣,兩個陣列比較,陣列型別要一樣。
2.隨機數生成與氣泡排序

func main() {
   //設定種子,只需一次
   //如果種子引數一樣,每次允許程式產生的隨機數都一樣
   //解決辦法,用時間
   rand.Seed(time.Now().UnixNano()) //以當前系統時間作為種子引數

   var a [10]int
   n := len(a)
   for i:=0; i < n; i++{
       //產生隨機數
       //fmt.Println("rand = ", rand.Int()) //隨機很大的數
       a[i]= rand.Intn(100)
       fmt.Printf("%d, ", a[i]) //Intn函式,限定隨機數生成的範圍
   }
   fmt.Printf("\n")

   //氣泡排序,挨著的2個元素比較,升序(大於交換)
   for i :=0; i<n-1; i++{
       for j :=0;j<n-1-i;j++{
           if a[j]>a[j+1]{
               a[j], a[j+1] = a[j+1], a[j]
           }
       }
   }
   fmt.Println("有序後:")
    for i:=0; i < n; i++{
        fmt.Printf("%d, ", a[i]) //Intn函式,限定隨機數生成的範圍
    }
   }

陣列做函式引數,它是值傳遞。實引數組的每個元素給行引數組拷貝一份。如果需要用函式改變陣列的值,用指標。

//陣列做函式引數,它是值傳遞
//實引數組的每個元素給行引數組拷貝一份
func  modify(p *[5]int)  {
    (*p)[0] = 666
    fmt.Println("*a = ", *p)
}
func main() {

    a :=[5]int{1,2,3,4,5}
    modify(&a)
    fmt.Println(a)
}

2.切片

func main() {
   array := [...]int {10, 20, 30, 0, 0}
   s := array[0:3:5]
    //[low:high:max]
    //low下標的起點
    //high下標的終點(不包括此下標),左閉右開
    //len=high-low
    //cap = max - low 容量
    fmt.Println("s = ", s)
    fmt.Println("len(s) = ", len(s))  //長度=3-0
    fmt.Println("cap(s) = ", cap(s))  //容量=5-0
   
   //切片與陣列的區別
   //陣列[]裡面的長度是固定的一個常量,陣列不能修改長度,len和cap永遠固定
    a := [5]int{}
    fmt.Printf("len = %d, cap = %d\n", len(a), cap(a))

    //切片,[]裡面為空,或者為...切片的長度或容量可以不固定
    s := []int{}
    fmt.Printf("len = %d, cap = %d\n", len(s), cap(s))
    
    s = append(s, 11)  //給切片末尾增加一個成員
}

切片的建立

//自動推導型別,同時初始化
   s1 := []int{1, 2, 3, 4}
   fmt.Println("s1 =", s1)

   //藉助make函式,格式make(切片型別, 長度, 容量)
   s2 := make([]int, 5, 10)
   fmt.Printf("len = %d, cap = %d\n", len(s2), cap(s2))
   //容量可預設,預設時容量等於長度

切片操作

array := []int{0,1,2,3,4,5,6,7,8,9}
   s1 := array[:] //[0:len(array):len(array)],不指定時容量和長度一樣
   fmt.Println(s1)
   fmt.Printf("len = %d, cap = %d\n", len(s1), cap(s1))

   //操作某個元素,和陣列操作方式一樣
   data := array[0]
   fmt.Println(data)
   s2 := array[3:6:7]
   fmt.Printf("len = %d, cap = %d\n", len(s2), cap(s2))
   s3 := array[:6]  //從0開始,取6個元素,容量為10
   fmt.Printf("len = %d, cap = %d\n", len(s3), cap(s3))
   s4 := array[3:]  //從下標為3開始到結尾
   fmt.Println(s4)  //取7個元素,容量為7
   fmt.Printf("len = %d, cap = %d\n", len(s4), cap(s4))

切片與底層陣列的關係

array := []int{0,1,2,3,4,5,6,7,8,9}
   //新切片修改後原陣列也發生改變
   s1 := array[2:5]
   s1[1] = 666
   fmt.Println(s1)
   fmt.Println(array)
   fmt.Printf("len = %d, cap = %d\n", len(s1), cap(s1))

   //另外新切片,切片的切片
   s2 := s1[2:7]
   s2[2] = 777
   fmt.Println(s2)
    fmt.Println(array)

使用append函式,如果超過原來的容量,通常以2倍容量擴容

func test(m map[int]string){
    delete(m,2)
}
func main() {
     var ml map[int]string
     fmt.Println("ml =", ml)
     //隊友map只有len,沒有cap
     fmt.Println("len =",len(ml))

     //可以通過make建立
     m2 := make(map[int]string)
    fmt.Println("ml =", m2)
    fmt.Println("len =", len(m2))

     //可通過make建立指定長度,只是指定了容量,長度由map內資料決定
    m3 := make(map[int]string,10)
    m3[1] = "mike"
    m3[20] = "c++"
    m3[50] = "go"
    fmt.Println("ml =", m3)
    fmt.Println("len =", len(m3))

    //初始化,且鍵值唯一
    m4 := map[int]string{1: "mike", 2: "go", 3: "c++"}
    fmt.Println("m4 =", m4)

    //遍歷
    for key, value := range m4 {
        fmt.Printf("%d ====> %s\n", key, value)
    }

    //如何判斷一個key是否存在
    //第一個返回值為key所對應的value,第二個返回值為key是否存在的條件,存在ok為true
    value, ok := m4[1]
    if ok == true{
        fmt.Println("m[1] =",value)
    }else{
        fmt.Printf("key不存在\n")
    }

    //刪除某個值
    delete(m4, 1)  //刪除key為1的內容
    fmt.Println(m4)

    //將刪除操作寫在函式內部
    test(m4) //在函式內部刪除某個key
    fmt.Println("m4 = ", m4)
}

2.定義結構體

//結構體型別
//有時我們需要將不同資料型別的數組合成一個有機的整體

//定義一個結構體型別
type Student struct{
    id int
    name string
    sex byte
    age int
    addr string
}

func main() {
    //順序初始化,每個成員必須初始化
    var s1 Student = Student{1,"mike", 'm', 18, "bj"}
    fmt.Println("s1 =", s1)

    //指定成員初始化,沒有初始化
    s2 := Student{name: "mike", addr: "bj"}
    fmt.Println("s2 =", s2)

    //初始化指標變數
    var s3 *Student = &Student{1,"mike", 'm', 18, "bj"}
    fmt.Println("s3 =", *s3)
    s4 := &Student{name: "mike", addr: "bj"}
    fmt.Println("s4 =", *s4)
}

結構體指標變數

 //1.指標有合法指向後,才操作成員
   //先定義一個普通結構體變數
   var s Student
   //再定義一個指標變數,儲存s的地址
   var p1 *Student
   p1 = &s

   //通過指標操作成員,p1.id和(*p).id完全等價,只能用.運算子
   p1.id = 1
   p1.name = "mike"
   p1.sex = 'm'
   p1.age = 18
   p1.addr = "bj"
   fmt.Println("p1 = ",p1)

   //2.通過new申請一個結構體
   p2 :=new(Student)
    p2.id = 1
    (*p2).name = "mike"
    p2.sex = 'm'
    p2.age = 18
    p2.addr = "bj"
    fmt.Println("p2 = ",p2)

如果想使用別的包的函式,結構體型別,結構體成員
函式名,型別名,結構體成員變數名,首字母必須大寫,可見
如果首字母是小寫,只能在同一個包裡使用