go基礎編程day4切片slice與map

切片slice

  • 本身并不是數(shù)組,它指向底層的數(shù)組

  • 作為變長數(shù)組的替代方案,可以關聯(lián)底層數(shù)組的局部或者全部

  • 為引用類型

  • 可以直接創(chuàng)建或從底層數(shù)組獲取生成

  • 使用len()獲取元素個數(shù),cap()獲取當前容量

  • 一般使用make()創(chuàng)建

  • 如果多個slice指向相同底層數(shù)組,其中一個slice的值的改變會影響全部

  • make([]type, len, cap)

  • 其中cap可以省略,則和len的值相同

  • len表示存數(shù)的元素個數(shù),cap表示容量

package main

import (
    "fmt"
)

// 創(chuàng)建slice
func main() {
    // 聲明空slice
    var s1 []int
    fmt.Println(s1) // []
    // 切片生成slice
    a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
    s2 := a[5:]
    fmt.Println(s2, len(s2), cap(s2)) // [6 7 8 9 0] 5 5
    // make生成slice
    s3 := make([]int, 3, 10)
    fmt.Println(s3, len(s3), cap(s3)) // [0 0 0] 3 10
}

reslice

  • replace時索引以被slice的切片為準
  • 索引不可以超過被slice的切片的容量cap()的值(注意這里是容量,并不是長度,即便取長度外的值,只要不超過容量,依然可以取到值)
  • 索引越界不會導致底層數(shù)組的重新分配而是引發(fā)錯誤

如果是切片生成的slice則要注意幾點:

package main

import (
    "fmt"
)

func main() {
    // 切片生成slice
    a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
    s2 := a[3:5]
    fmt.Println(s2, len(s2), cap(s2)) // [4 5] 2 7
    // 對長度為2的s2進行切片取長度外的值依然能取到
    s3 := s2[3:5]
    fmt.Println(s3) // [7 8]
}

這里要明確的是s2取到的slice雖然長度只有2但是他的最大容量是到原數(shù)組尾部的,并且,slice是引用的一個地址,所以能取到后面的值

append

  • 可以在slice尾部追加元素
  • 可以將一個slice追加到另一個slice尾部
  • 如果最終長度未超過追加到slice的容量則返回原始slice
  • 如果超過追加到的slice的容量則將重新分配數(shù)組并拷貝原始數(shù)據(jù)
package main

import (
    "fmt"
)

func main() {
    s1 := make([]int, 3, 6)
    fmt.Printf("%p\n", s1) // 0xc420084030
    s1 = append(s1, 1, 2, 3)
    fmt.Printf("%p\n", s1) // 0xc420084030
    s1 = append(s1, 1, 2, 3)
    // 第三次內存地址發(fā)生改變,超出原有容量
    fmt.Printf("%p\n", s1) // 0xc42007a060
}
package main

import (
    "fmt"
)

func main() {
    a := []int{1, 2, 3, 4, 5}
    s1 := a[2:5]
    s2 := a[1:3]
    fmt.Println(s1, s2)
    s1[0] = 9
    // 改變了s1,s1,s2和a都改變了
    fmt.Println(s1, s2, a)
}

copy

package main

import (
    "fmt"
)

func main() {
    s1 := make([]int, 5, 10)
    s2 := []int{7, 8, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1}
    // 第一個參數(shù)是copy到的目標,第二個是被copy的
    // 這里是將s2 copy到 s1
    copy(s1, s2)
    fmt.Println(s1) // [7 8 9 4 5 6]
}

/*
總結
copy最后的長度為copy目標的長度(非容量)
copy到對象的長度能容納多少就會容納多少
如果被copy的對象長度較小,按照順序copy,剩下的原封不動
*/

map(類似字典)

  • 類似其他語言中的哈希表或者字典,以k_v形式存儲數(shù)據(jù)

  • key必須是支持==或者!=比較運算的類型,不可以是函數(shù)、map或slice

  • map查找比線性搜索快很多,但比使用索引訪問數(shù)據(jù)的類型慢100倍

  • map使用make()創(chuàng)建,支持:=這種簡寫方式

  • make([keytype]valuetype, cap),cap表示容量,可以省略

  • 超出容量時會自動擴容,但盡量供一個合理的初始值

  • 使用len()獲取元素個數(shù)

  • 鍵值對不存在時自動添加,使用delete()刪除某個鍵值對
  • 使用for range對map和slice進行迭代操作
package main

import (
    "fmt"
)

func main() {
    // 第一種方式
    var m map[int]string
    m = map[int]string{}
    fmt.Println(m)
    // 第二種方式
    var m1 map[int]string = make(map[int]string)
    fmt.Println(m1)
    // 第三種其實就是去掉第二種中多余的部分
    var m2 = make(map[int]string)
    fmt.Println(m2)
    // 簡潔方式
    m3 := make(map[int]string)
    fmt.Println(m3)
}

增刪

package main

import (
    "fmt"
)

func main() {
    m := make(map[int]string)
    m[1] = "ok"
    a:=m[1]
    b:= m[2]
    fmt.Println(m) // map[1:ok]
    fmt.Println(a) // ok
    fmt.Println(b) // 此處取出的為空
    delete(m,1)
    fmt.Println(m[1]) // 刪除了
}

復雜map

package main

import "fmt"

func main() {
    m := make(map[int]map[int]string)
    // 如果map內層還有map,內層的map也要初始化
        // 如果不初始化則取出的為空字符,并且賦值的時候報錯
    m[1] = make(map[int]string)
    m[1][1] = "ok"
    a := m[1][1]
    fmt.Println(a) // ok
}

如何知道內層map是否已經(jīng)初始化了(防止賦值的時候報錯)

package main

import "fmt"

func main() {
    m := make(map[int]map[int]string)
    a := m[1][1]
    fmt.Println(a) // 此時輸出為空字符串
    b, ok := m[1][1]
    fmt.Println(b, ok) // 空字符串和false
}
// 這個時候就可以加個判斷,如果第二個返回值為false就說明沒有初始化,否則已經(jīng)初始化了

對slice和map進行迭代操作

對元素為map的slice進行迭代的時候,獲取到的v是值的copy,所以不能真正修改slice中map的值這個時候迭代k通過k來直接修改map

// 迭代一個內容為map的slice
func main() {
    // 5個map
    sm := make([]map[int]string, 5)
    // 想真正修改被迭代對象的值,需要迭代索引,利用索引直接修改迭代對象
    for i := range sm {
        sm[i] = make(map[int]string, 1)
        sm[i][1] = "ok"
        fmt.Println(sm[i])
    }
    fmt.Println(sm)


    /*
    map[1:ok]
    map[1:ok]
    map[1:ok]
    map[1:ok]
    map[1:ok]
    [map[1:ok] map[1:ok] map[1:ok] map[1:ok] map[1:ok]]
    
    */
}

map是無序的,但是可以通過key進行間接排序:排序k,通過有序的k來取map中的v

package main

import (
    "fmt"
    "sort"
)

func main() {
    m := map[int]string{1: "a", 2: "b", 3: "c", 4: "d", 5: "e"}
    s := make([]int, len(m))
    i := 0
    // 將map中的k存在slice中
    for k := range m {
        s[i] = k
        i++
    }
    // 排序slice
    sort.Ints(s)
    fmt.Println(s)
    // 完成了對k的排序之后就可以有序取map中的值
}

map k-v調換位置

package main

import (
    "fmt"
)

func main() {
    m1 := map[int]string{1: "a", 2: "b", 3: "c", 4: "d", 5: "e"}
    m2 := make(map[string]int)
    fmt.Println(m1)
    for k,v := range m1{
        m2[v] = k
    }
    fmt.Println(m2)
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容