Go語言數(shù)組和切片

此處數(shù)組只講Go語言中和C語言不一樣的地方

  • 格式不同:
    Go語言定義數(shù)組的格式:var ages [3]int

定義的同時初始化

格式 var 數(shù)組名稱 數(shù)組類型 = 數(shù)組類型{值}

var ages [3]int = [3]int{1,3,5}
  • 注意點:
    1.在定義的同時初始化必須在大括號前寫上數(shù)據(jù)類型,并且數(shù)據(jù)類型必須相同(數(shù)組長度和數(shù)據(jù)類型)

    2.可以和C語言一樣部分初始化,但是C語言部分初始化沒有被賦值的地方保存了垃圾數(shù)據(jù),Go語言中沒有被賦值的地方默認(rèn)為0\

    3.數(shù)組中數(shù)組的名稱不能代表數(shù)組的地址


  • 第二種方式(省略數(shù)組長度)
ages := [...]int{1,3,5}
  • 在這里用...表示數(shù)組長度,編譯器根據(jù)賦值的元素個數(shù)自動計算數(shù)組的元素個數(shù)

先定義后初始化

var ages [3]int
ages = [3]int{1,3,5}
  • 在這里,Go語言可以一次性給數(shù)組賦值,當(dāng)然也可以逐個賦值

數(shù)組注意點

  1. Go語言中數(shù)組是值類型,數(shù)組之間的賦值是值拷貝,而不是地址的拷貝
ages := [3]int{1,3,5}
change(ages)
fmt.println(ages)//1,3,5


func change(num [3]int) {
    num[1] = 666
}

2.由于數(shù)組是值類型,所以兩個數(shù)組間可以用" == " " != "進(jìn)行比較,但是進(jìn)行值比較的數(shù)組必須類型長度完全相同,完全相同!!!


數(shù)組的遍歷

  • 方法一: 傳統(tǒng)的for循環(huán)
  • 方法二: for index,value := range ages{
    fmt.println(index,value)
    }

二維數(shù)組

  • 定義二維數(shù)組的格式
    var 數(shù)組名稱 [行數(shù)][列數(shù)]數(shù)據(jù)類型
    var 數(shù)組名稱 [一維數(shù)組的個數(shù)][每個一維數(shù)組的元素個數(shù)]數(shù)據(jù)類型
  • 注意點:
    二維數(shù)組也可以省略元素個數(shù), 但是只能省略行數(shù), 不能省略列數(shù)

切片(重點)

  • 數(shù)組的長度一旦固定,就不能改變,Go語言為了解決這一問題,產(chǎn)生了切片,切片就是可變的數(shù)組
  • 切片的底層是結(jié)構(gòu)體
    Go語言源碼中如此展示
type slice struct{
      array unsafe.Pointer // 指向底層數(shù)組指針
      len int // 切片長度(保存了多少個元素)
      cap int // 切片容量(可以保存多少個元素)
    }

創(chuàng)建切片的方式

  • 方法一: 通過數(shù)組來創(chuàng)造切片

    • 格式:[起始位置:結(jié)束位置] 包括起始位置但不包括結(jié)束位置,左閉右開的區(qū)間
    • 注意點:
      • 切片的長度(len)等于截取到的數(shù)組的長度

      • 切片的容量(cap)等于數(shù)組的長度減去切片的起始位置

      • 如果不寫起始位置,就是從第0個開始截取

      • 如果不寫結(jié)束位置,就是截取到末尾

var ages[5] = [5]int{1,3,5,7,9}
var sce[] = ages[2:]
fmt.println(sce)//[5,7,9]
fmt.println(len(sce))//3
fmt.println(cap(sce))//3

var sce2[] = ages[:2]
fmt.println(sce2)//[1,3]
fmt.println(len(sce2))//2
fmt.println(cap(sce2))//5

  • 方法二: 通過make函數(shù)創(chuàng)建
    • 格式:make([]數(shù)據(jù)類型,長度,容量)

      1. 第一個參數(shù): 創(chuàng)建的數(shù)據(jù)類型,創(chuàng)建切片前一定要加[]

      2. 第二個參數(shù): 告訴系統(tǒng)創(chuàng)建切片的長度

      3.第三個參數(shù): 告訴系統(tǒng)創(chuàng)建切片的容量(如果第三個參數(shù)不寫,那么第三個長度默認(rèn)和切片的長度相等)

var sce []int = make([]int, 2)
    fmt.Println(sce)//[0,0]
    fmt.Println(len(sce))//2
    fmt.Println(cap(sce))//2

  • 方法三: 通過Go語言提供的語法糖創(chuàng)建
    • 中括號沒有值就是切片
    • 特點:用Go語法糖創(chuàng)建的切片的長度和容量相等
    • var ages []int = []int{1,3,5,7,9}

切片的使用

  • 使用方法一: 切片是可變長度的數(shù)組,所以可以像數(shù)組一樣使用切片,但是索引的長度不能超過切片的len
var sce []int = make([]int,2,5)
sce[2] = 999//報錯,索引大于切片長度
fmt.println(sce)
  • 使用方法二: 可以通過預(yù)先定義好的函數(shù)來使用切片

    • append函數(shù)
    • append(切片,數(shù)據(jù))

    • append函數(shù)作用是在切片len后面添加數(shù)據(jù)

  • 注意點:

    • 在append函數(shù)后面追加的數(shù)據(jù)超過了切片的cap,那么切片會按照當(dāng)前容量*2的方式重新擴(kuò)容,并且sce[0]的值和擴(kuò)容前的值相等,說明將源切片拷貝了一份作為新切片,切片的地址會發(fā)生改變

    • append函數(shù)返回一個切片,由于append擴(kuò)容的時候需要創(chuàng)建一個新的切片,所以返回一個切片

    • 如果容量不超過1024時,擴(kuò)容的時候會按照cap*2擴(kuò)容,如果容量超過1024,擴(kuò)容的時候會按照原來cap的1/2擴(kuò)容

    • 如果append追加的數(shù)據(jù)未超過切片的cap,雖然返回一個切片,但是切片的地址沒有改變,如果append追加的數(shù)據(jù)超過了切片的cap,那么返回的切片的地址會發(fā)生改變

var sce []int = make([]int, 2, 3)
fmt.Printf("%p\n",sce)//0xc0420520c0
sce = append(sce, 3)
fmt.Printf("%p",sce)//0xc0420520c0


var sce2 []int = make([]int, 2, 2)
fmt.Printf("%p\n",sce)//0xc0420080c0
sce = append(sce2, 3)
fmt.Printf("%p",sce2)//0xc04200e300
  • 使用方法三:
    • 切片的增刪改查
      • 增(append函數(shù))

      • 改(切片名稱[索引] = 值)


      • for _,value in range 切片名稱{
        if value == 3 {
        fmt.Println("包含數(shù)字3")
        }
        }

          • 我們不僅可以通過數(shù)組創(chuàng)建切片,還能通過切片創(chuàng)建切片
          • 通過切片創(chuàng)建的切片,兩個切片指向同一個數(shù)組
          • 切片的刪就是將第二次截取的切片添加到第一次截取的切片后面即可
          • append(sce[:index],sce[index+1:])
var ages []int = []int{1,3,5,7,9,11}
//假如需要刪掉的索引是3(值為7)
var sce []int = ages[:3]
var sce2 []int = ages[4:]
sce3 = append(sce,sce2)
fmt.Println(sce)//[1,3,5,9,11]

數(shù)組和切片的辨別

  • 只要定義的時候中括號里有東西,哪怕是...,那定義的就是數(shù)組不是切片

切片和函數(shù)

  • 可變參數(shù)的函數(shù),其中可變參數(shù)底層原理就是切片
  • 注意點: 如果函數(shù)編寫了可變參數(shù), 那么可變參數(shù)只能放在形參列表的最后
    res:=sum(10, 20, 30)
    fmt.Println(res)//60
}

// 注意點: 如果函數(shù)編寫了可變參數(shù), 那么可變參數(shù)只能放在形參列表的最后
func sum(nums ...int) int{
//func sum(value float32, nums ...int) int{
    var res int
    for _,value := range nums {
        res += value
        fmt.Println(value)
    }

    return res
}
func sum(nums []int) int{
    // 2.遍歷切片
    var res int
    for _, value := range nums{
        res += value
    }
    return res
}

  • copy函數(shù)
    • copy(目標(biāo)切片, 源切片)

    • 注意點:

      • 如果目標(biāo)切片的容量大于了源切片的容量,那么源切片會一一將數(shù)據(jù)覆蓋到目標(biāo)切片上

      • 如果目標(biāo)切片的容量小于了源切片的容量,那么源切片會一一將數(shù)據(jù)覆蓋到目標(biāo)切片上,多余的數(shù)據(jù)會被剔除

    sce1 := []int{1, 3} // 源切片
    sce2 := []int{2, 4, 6} // 目標(biāo)切片
    fmt.Println(sce2)
    copy(sce1, sce2)
    fmt.Println(sce1)//[2,4]

切片的注意點

1.切片可以再生成新的切片, 兩個切片底層指向同一個數(shù)組

2.切片和數(shù)組不同, 切片不支持== !=操作

3.在Go語言中字符串的底層實現(xiàn)就是切片, 所以可以通過字符串來生成切片

//需求:將字符串"www.it666.com"的首字母改為M
var str string = "www.it666.com"
sce := make([]byte,len(str))
copy(sce,str)
sce[0] = 'M'
fmt.Printf("%s\n", sce)
  1. 通過數(shù)組創(chuàng)建切片補充

    格式: 數(shù)組名稱[low: high: max]

    注意點:

    • max必須大于第二個參數(shù)

    • 如果max不寫,那么cap就等于數(shù)組長度 - 第一個參數(shù)

    • 如果寫上max,那么cap就等于max - 第一個參數(shù)

var arr [6]int = [6]int{1,3,5,7,9,11}
var sce []int = arr[2:4:4]
fmt.Println(sce) // [5,7]
fmt.Println(len(sce)) // 2
fmt.Println(cap(sce)) // 2
  1. 僅僅定義, 沒有初識的數(shù)組是可以使用的, 但是僅僅定義但是沒有初始化的切片是不能使用的
var sce []int
//sce[0] = 666  編譯報錯
//sce[1] = 888  編譯報錯
sce = make([]int, 3, 5)
sce[0] = 666
sce[1] = 888
sce[2] = 999
fmt.Println(sce) // [666,888,999]
var sce []int
sce = append(sce, 1)
sce = append(sce, 2)
sce = append(sce, 3)
fmt.Println(sce) // [1,2,3]
  1. 切片計算長度不能用unsafe.Sizeof(sce),切片本質(zhì)是一個結(jié)構(gòu)體,所以Sizeof實際上計算的是結(jié)構(gòu)體的內(nèi)存,在64位機(jī)上為24
    var sce []int = []int{1, 3, 5, 7, 9}
        //推薦方式:
        length := len(sce)
        fmt.Println(length)

數(shù)組和切片作為函數(shù)參數(shù)的區(qū)別

  • 數(shù)組作為函數(shù)參數(shù),是值傳遞,函數(shù)內(nèi)改變不會改變實參的值

  • 切片作為函數(shù)參數(shù),是地址傳遞,函數(shù)內(nèi)改變會改變實參的值

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末饺鹃,一起剝皮案震驚了整個濱河市盟庞,隨后出現(xiàn)的幾起案子罩抗,更是在濱河造成了極大的恐慌捌臊,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)迹冤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來虎忌,“玉大人泡徙,你說我怎么就攤上這事∧ご溃” “怎么了堪藐?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長挑围。 經(jīng)常有香客問我礁竞,道長,這世上最難降的妖魔是什么杉辙? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任模捂,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘狂男。我一直安慰自己综看,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布岖食。 她就那樣靜靜地躺著寓搬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪县耽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天镣典,我揣著相機(jī)與錄音兔毙,去河邊找鬼。 笑死兄春,一個胖子當(dāng)著我的面吹牛澎剥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赶舆,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼哑姚,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了芜茵?” 一聲冷哼從身側(cè)響起叙量,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎九串,沒想到半個月后绞佩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡猪钮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年品山,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片烤低。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡肘交,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出扑馁,到底是詐尸還是另有隱情涯呻,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布檐蚜,位于F島的核電站魄懂,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏闯第。R本人自食惡果不足惜市栗,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧填帽,春花似錦蛛淋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嘹悼,卻和暖如春叛甫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背杨伙。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工其监, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人限匣。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓抖苦,卻偏偏與公主長得像,于是被迫代替她去往敵國和親米死。 傳聞我的和親對象是個殘疾皇子锌历,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容