久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Go 經(jīng)典入門系列 11:數(shù)組和切片

 F2967527 2020-12-09

歡迎來到 Golang 系列教程的第 11 章。在本章教程中,,我們將討論 Go 語言中的數(shù)組和切片,。

數(shù)組

數(shù)組是同一類型元素的集合。例如,,整數(shù)集合 5,8,9,79,76 形成一個數(shù)組,。Go 語言中不允許混合不同類型的元素,例如包含字符串和整數(shù)的數(shù)組,。(譯者注:當然,,如果是 interface{} 類型數(shù)組,可以包含任意類型)

數(shù)組的聲明

一個數(shù)組的表示形式為 [n]T,。n 表示數(shù)組中元素的數(shù)量,,T 代表每個元素的類型,。元素的數(shù)量 n 也是該類型的一部分(稍后我們將詳細討論這一點)。

可以使用不同的方式來聲明數(shù)組,,讓我們一個一個的來看,。

package main

import (
    'fmt'
)

func main() {
    var a [3]int //int array with length 3
    fmt.Println(a)
}

在線運行程序

var a[3]int 聲明了一個長度為 3 的整型數(shù)組。數(shù)組中的所有元素都被自動賦值為數(shù)組類型的零值,。 在這種情況下,,a 是一個整型數(shù)組,因此 a 的所有元素都被賦值為 0,,即 int 型的零值,。運行上述程序?qū)?輸出 [0 0 0]

數(shù)組的索引從 0 開始到 length - 1 結(jié)束,。讓我們給上面的數(shù)組賦值,。

package main

import (
    'fmt'
)

func main() {
    var a [3]int //int array with length 3
    a[0] = 12 // array index starts at 0
    a[1] = 78
    a[2] = 50
    fmt.Println(a)
}

在線運行程序

a[0] 將值賦給數(shù)組的第一個元素。該程序?qū)?輸出 [12 78 50],。

讓我們使用 簡略聲明 來創(chuàng)建相同的數(shù)組,。

package main

import (
    'fmt'
)

func main() {
    a := [3]int{127850// short hand declaration to create array
    fmt.Println(a)
}

在線運行程序

上面的程序?qū)蛴∠嗤?輸出 [12 78 50]

在簡略聲明中,,不需要將數(shù)組中所有的元素賦值。

package main

import (
    'fmt'
)

func main() {
    a := [3]int{12}
    fmt.Println(a)
}

在線運行程序

在上述程序中的第 8 行 a := [3]int{12} 聲明一個長度為 3 的數(shù)組,,但只提供了一個值 12,,剩下的 2 個元素自動賦值為 0。這個程序?qū)?strong>輸出 [12 0 0],。

你甚至可以忽略聲明數(shù)組的長度,,并用 ... 代替,讓編譯器為你自動計算長度,,這在下面的程序中實現(xiàn),。

package main

import (
    'fmt'
)

func main() {
    a := [...]int{127850// ... makes the compiler determine the length
    fmt.Println(a)
}

在線運行程序

數(shù)組的大小是類型的一部分。因此 [5]int[25]int 是不同類型,。數(shù)組不能調(diào)整大小,,不要擔心這個限制,因為 slices 的存在能解決這個問題,。

package main

func main() {
    a := [3]int{5788}
    var b [5]int
    b = a // not possible since [3]int and [5]int are distinct types
}

在線運行程序

在上述程序的第 6 行中, 我們試圖將類型 [3]int 的變量賦給類型為 [5]int 的變量,,這是不允許的,因此編譯器將拋出錯誤 main.go:6: cannot use a (type [3]int) as type [5]int in assignment,。

數(shù)組是值類型

Go 中的數(shù)組是值類型而不是引用類型,。這意味著當數(shù)組賦值給一個新的變量時,該變量會得到一個原始數(shù)組的一個副本,。如果對新變量進行更改,,則不會影響原始數(shù)組,。

package main

import 'fmt'

func main() {
    a := [...]string{'USA''China''India''Germany''France'}
    b := a // a copy of a is assigned to b
    b[0] = 'Singapore'
    fmt.Println('a is ', a)
    fmt.Println('b is ', b)
}

在線運行程序

在上述程序的第 7 行,a 的副本被賦給 b,。在第 8 行中,,b 的第一個元素改為 Singapore。這不會在原始數(shù)組 a 中反映出來,。該程序?qū)?輸出,

a is [USA China India Germany France]
b is [Singapore China India Germany France]

同樣,,當數(shù)組作為參數(shù)傳遞給函數(shù)時,它們是按值傳遞,,而原始數(shù)組保持不變,。

package main

import 'fmt'

func changeLocal(num [5]int) {
    num[0] = 55
    fmt.Println('inside function ', num)
}
func main() {
    num := [...]int{56788}
    fmt.Println('before passing to function ', num)
    changeLocal(num) //num is passed by value
    fmt.Println('after passing to function ', num)
}

在線運行程序

在上述程序的 13 行中, 數(shù)組 num 實際上是通過值傳遞給函數(shù) changeLocal,數(shù)組不會因為函數(shù)調(diào)用而改變,。這個程序?qū)⑤敵?

before passing to function  [5 6 7 8 8]
inside function  [55 6 7 8 8]
after passing to function  [5 6 7 8 8]

數(shù)組的長度

通過將數(shù)組作為參數(shù)傳遞給 len 函數(shù),,可以得到數(shù)組的長度。

package main

import 'fmt'

func main() {
    a := [...]float64{67.789.82178}
    fmt.Println('length of a is',len(a))
}

在線運行程序

上面的程序輸出為 length of a is 4,。

使用 range 迭代數(shù)組

for 循環(huán)可用于遍歷數(shù)組中的元素,。

package main

import 'fmt'

func main() {
    a := [...]float64{67.789.82178}
    for i := 0; i < len(a); i++ { // looping from 0 to the length of the array
        fmt.Printf('%d th element of a is %.2f\n', i, a[i])
    }
}

在線運行程序

上面的程序使用 for 循環(huán)遍歷數(shù)組中的元素,從索引 0length of the array - 1,。這個程序運行后打印出,,

0 th element of a is 67.70
1 th element of a is 89.80
2 th element of a is 21.00
3 th element of a is 78.00

Go 提供了一種更好、更簡潔的方法,,通過使用 for 循環(huán)的 range 方法來遍歷數(shù)組,。range 返回索引和該索引處的值。讓我們使用 range 重寫上面的代碼,。我們還可以獲取數(shù)組中所有元素的總和,。

package main

import 'fmt'

func main() {
    a := [...]float64{67.789.82178}
    sum := float64(0)
    for i, v := range a {//range returns both the index and value
        fmt.Printf('%d the element of a is %.2f\n', i, v)
        sum += v
    }
    fmt.Println('\nsum of all elements of a',sum)
}

在線運行程序

上述程序的第 8 行 for i, v := range a 利用的是 for 循環(huán) range 方式。它將返回索引和該索引處的值,。我們打印這些值,,并計算數(shù)組 a 中所有元素的總和。程序的 輸出是,,

0 the element of a is 67.70
1 the element of a is 89.80
2 the element of a is 21.00
3 the element of a is 78.00

sum of all elements of a 256.5

如果你只需要值并希望忽略索引,,則可以通過用 _ 空白標識符替換索引來執(zhí)行。

for _, v := range a { // ignores index
}

上面的 for 循環(huán)忽略索引,,同樣值也可以被忽略,。

多維數(shù)組

到目前為止我們創(chuàng)建的數(shù)組都是一維的,Go 語言可以創(chuàng)建多維數(shù)組,。

package main

import (
    'fmt'
)

func printarray(a [3][2]string) {
    for _, v1 := range a {
        for _, v2 := range v1 {
            fmt.Printf('%s ', v2)
        }
        fmt.Printf('\n')
    }
}

func main() {
    a := [3][2]string{
        {'lion''tiger'},
        {'cat''dog'},
        {'pigeon''peacock'}, // this comma is necessary. The compiler will complain if you omit this comma
    }
    printarray(a)
    var b [3][2]string
    b[0][0] = 'apple'
    b[0][1] = 'samsung'
    b[1][0] = 'microsoft'
    b[1][1] = 'google'
    b[2][0] = 'AT&T'
    b[2][1] = 'T-Mobile'
    fmt.Printf('\n')
    printarray(b)
}

在線運行程序

在上述程序的第 17 行,,用簡略語法聲明一個二維字符串數(shù)組 a 。20 行末尾的逗號是必需的。這是因為根據(jù) Go 語言的規(guī)則自動插入分號,。至于為什么這是必要的,,如果你想了解更多,請閱讀https:///doc/effective_go.html#semicolons,。

另外一個二維數(shù)組 b 在 23 行聲明,,字符串通過每個索引一個一個添加。這是另一種初始化二維數(shù)組的方法,。

第 7 行的 printarray 函數(shù)使用兩個 range 循環(huán)來打印二維數(shù)組的內(nèi)容,。上述程序的 輸出是

lion tiger
cat dog
pigeon peacock

apple samsung
microsoft google
AT&T T-Mobile

這就是數(shù)組,盡管數(shù)組看上去似乎足夠靈活,,但是它們具有固定長度的限制,,不可能增加數(shù)組的長度。這就要用到 切片 了,。事實上,,在 Go 中,切片比傳統(tǒng)數(shù)組更常見,。

切片

切片是由數(shù)組建立的一種方便,、靈活且功能強大的包裝(Wrapper)。切片本身不擁有任何數(shù)據(jù),。它們只是對現(xiàn)有數(shù)組的引用,。

創(chuàng)建一個切片

帶有 T 類型元素的切片由 []T 表示

package main

import (
    'fmt'
)

func main() {
    a := [5]int{7677787980}
    var b []int = a[1:4// creates a slice from a[1] to a[3]
    fmt.Println(b)
}

在線運行程序

使用語法 a[start:end] 創(chuàng)建一個從 a 數(shù)組索引 start 開始到 end - 1 結(jié)束的切片。因此,,在上述程序的第 9 行中, a[1:4] 從索引 1 到 3 創(chuàng)建了 a 數(shù)組的一個切片表示,。因此, 切片 b 的值為 [77 78 79]

讓我們看看另一種創(chuàng)建切片的方法,。

package main

import (
    'fmt'
)

func main() {
    c := []int{678// creates and array and returns a slice reference
    fmt.Println(c)
}

在線運行程序

在上述程序的第 9 行,c:= [] int {6,,7,,8} 創(chuàng)建一個有 3 個整型元素的數(shù)組,并返回一個存儲在 c 中的切片引用,。

切片的修改

切片自己不擁有任何數(shù)據(jù),。它只是底層數(shù)組的一種表示。對切片所做的任何修改都會反映在底層數(shù)組中,。

package main

import (
    'fmt'
)

func main() {
    darr := [...]int{5789908210078676959}
    dslice := darr[2:5]
    fmt.Println('array before', darr)
    for i := range dslice {
        dslice[i]++
    }
    fmt.Println('array after', darr)
}

在線運行程序

在上述程序的第 9 行,,我們根據(jù)數(shù)組索引 2,3,4 創(chuàng)建一個切片 dslice。for 循環(huán)將這些索引中的值逐個遞增,。當我們使用 for 循環(huán)打印數(shù)組時,,我們可以看到對切片的更改反映在數(shù)組中。該程序的輸出是

array before [57 89 90 82 100 78 67 69 59]
array after [57 89 91 83 101 78 67 69 59]

當多個切片共用相同的底層數(shù)組時,每個切片所做的更改將反映在數(shù)組中,。

package main

import (
    'fmt'
)

func main() {
    numa := [3]int{7879 ,80}
    nums1 := numa[:] // creates a slice which contains all elements of the array
    nums2 := numa[:]
    fmt.Println('array before change 1', numa)
    nums1[0] = 100
    fmt.Println('array after modification to slice nums1', numa)
    nums2[1] = 101
    fmt.Println('array after modification to slice nums2', numa)
}

在線運行程序

在 9 行中,,numa [:] 缺少開始和結(jié)束值。開始和結(jié)束的默認值分別為 0len (numa),。兩個切片 nums1nums2 共享相同的數(shù)組,。該程序的輸出是

array before change 1 [78 79 80]
array after modification to slice nums1 [100 79 80]
array after modification to slice nums2 [100 101 80]

從輸出中可以清楚地看出,當切片共享同一個數(shù)組時,,每個所做的修改都會反映在數(shù)組中,。

切片的長度和容量

切片的長度是切片中的元素數(shù)。切片的容量是從創(chuàng)建切片索引開始的底層數(shù)組中元素數(shù),。

讓我們寫一段代碼來更好地理解這點,。

package main

import (
    'fmt'
)

func main() {
    fruitarray := [...]string{'apple''orange''grape''mango''water melon''pine apple''chikoo'}
    fruitslice := fruitarray[1:3]
    fmt.Printf('length of slice %d capacity %d'len(fruitslice), cap(fruitslice)) // length of is 2 and capacity is 6
}

在線運行程序

在上面的程序中,fruitslice 是從 fruitarray 的索引 1 和 2 創(chuàng)建的,。因此,,fruitlice 的長度為 2

fruitarray 的長度是 7,。fruiteslice 是從 fruitarray 的索引 1 創(chuàng)建的,。因此, fruitslice 的容量是從 fruitarray 索引為 1 開始,也就是說從 orange 開始,,該值是 6,。因此, fruitslice 的容量為 6。該程序輸出切片的 **長度為 2 容量為 6 **,。

切片可以重置其容量,。任何超出這一點將導致程序運行時拋出錯誤。

package main

import (
    'fmt'
)

func main() {
    fruitarray := [...]string{'apple''orange''grape''mango''water melon''pine apple''chikoo'}
    fruitslice := fruitarray[1:3]
    fmt.Printf('length of slice %d capacity %d\n'len(fruitslice), cap(fruitslice)) // length of is 2 and capacity is 6
    fruitslice = fruitslice[:cap(fruitslice)] // re-slicing furitslice till its capacity
    fmt.Println('After re-slicing length is',len(fruitslice), 'and capacity is',cap(fruitslice))
}

在線運行程序

在上述程序的第 11 行中,,fruitslice 的容量是重置的,。以上程序輸出為,

length of slice 2 capacity 6
After re-slicing length is 6 and capacity is 6

使用 make 創(chuàng)建一個切片

func make([]T,,len,,cap)[]T 通過傳遞類型,長度和容量來創(chuàng)建切片,。容量是可選參數(shù), 默認值為切片長度,。make 函數(shù)創(chuàng)建一個數(shù)組,并返回引用該數(shù)組的切片,。

package main

import (
    'fmt'
)

func main() {
    i := make([]int55)
    fmt.Println(i)
}

在線運行程序

使用 make 創(chuàng)建切片時默認情況下這些值為零,。上述程序的輸出為 [0 0 0 0 0]

追加切片元素

正如我們已經(jīng)知道數(shù)組的長度是固定的,,它的長度不能增加,。切片是動態(tài)的,,使用 append 可以將新元素追加到切片上。append 函數(shù)的定義是 func append(s[]T,,x ... T)[]T,。

x ... T 在函數(shù)定義中表示該函數(shù)接受參數(shù) x 的個數(shù)是可變的。這些類型的函數(shù)被稱為可變函數(shù),。

有一個問題可能會困擾你,。如果切片由數(shù)組支持,并且數(shù)組本身的長度是固定的,,那么切片如何具有動態(tài)長度,。以及內(nèi)部發(fā)生了什么,當新的元素被添加到切片時,,會創(chuàng)建一個新的數(shù)組?,F(xiàn)有數(shù)組的元素被復制到這個新數(shù)組中,并返回這個新數(shù)組的新切片引用?,F(xiàn)在新切片的容量是舊切片的兩倍,。很酷吧 :)。下面的程序會讓你清晰理解,。

package main

import (
    'fmt'
)

func main() {
    cars := []string{'Ferrari''Honda''Ford'}
    fmt.Println('cars:', cars, 'has old length'len(cars), 'and capacity'cap(cars)) // capacity of cars is 3
    cars = append(cars, 'Toyota')
    fmt.Println('cars:', cars, 'has new length'len(cars), 'and capacity'cap(cars)) // capacity of cars is doubled to 6
}

在線運行程序

在上述程序中,,cars 的容量最初是 3。在第 10 行,,我們給 cars 添加了一個新的元素,,并把 append(cars, 'Toyota') 返回的切片賦值給 cars。現(xiàn)在 cars 的容量翻了一番,,變成了 6,。上述程序的輸出是

cars: [Ferrari Honda Ford] has old length 3 and capacity 3
cars: [Ferrari Honda Ford Toyota] has new length 4 and capacity 6

切片類型的零值為 nil。一個 nil 切片的長度和容量為 0,??梢允褂?append 函數(shù)將值追加到 nil 切片。

package main

import (
    'fmt'
)

func main() {
    var names []string //zero value of a slice is nil
    if names == nil {
        fmt.Println('slice is nil going to append')
        names = append(names, 'John''Sebastian''Vinay')
        fmt.Println('names contents:',names)
    }
}

在線運行程序

在上面的程序 names 是 nil,,我們已經(jīng)添加 3 個字符串給 names,。該程序的輸出是

slice is nil going to append
names contents: [John Sebastian Vinay]

也可以使用 ... 運算符將一個切片添加到另一個切片。你可以在可變參數(shù)函數(shù)教程中了解有關此運算符的更多信息,。

package main

import (
    'fmt'
)

func main() {
    veggies := []string{'potatoes''tomatoes''brinjal'}
    fruits := []string{'oranges''apples'}
    food := append(veggies, fruits...)
    fmt.Println('food:',food)
}

在線運行程序

在上述程序的第 10 行,food 是通過 append(veggies, fruits...) 創(chuàng)建,。程序的輸出為 food: [potatoes tomatoes brinjal oranges apples],。

切片的函數(shù)傳遞

我們可以認為,切片在內(nèi)部可由一個結(jié)構體類型表示,。這是它的表現(xiàn)形式,,

type slice struct {
    Length        int
    Capacity      int
    ZerothElement *byte
}

切片包含長度、容量和指向數(shù)組第零個元素的指針。當切片傳遞給函數(shù)時,,即使它通過值傳遞,,指針變量也將引用相同的底層數(shù)組。因此,,當切片作為參數(shù)傳遞給函數(shù)時,,函數(shù)內(nèi)所做的更改也會在函數(shù)外可見。讓我們寫一個程序來檢查這點,。

package main

import (
    'fmt'
)

func subtactOne(numbers []int) {
    for i := range numbers {
        numbers[i] -= 2
    }
}
func main() {
    nos := []int{876}
    fmt.Println('slice before function call', nos)
    subtactOne(nos)                               // function modifies the slice
    fmt.Println('slice after function call', nos) // modifications are visible outside
}

在線運行程序

上述程序的行號 17 中,,調(diào)用函數(shù)將切片中的每個元素遞減 2。在函數(shù)調(diào)用后打印切片時,,這些更改是可見的,。如果你還記得,這是不同于數(shù)組的,,對于函數(shù)中一個數(shù)組的變化在函數(shù)外是不可見的,。上述程序的輸出是,

array before function call [8 7 6]
array after function call [6 5 4]

多維切片

類似于數(shù)組,,切片可以有多個維度,。

package main

import (
    'fmt'
)

func main() {
     pls := [][]string {
            {'C''C++'},
            {'JavaScript'},
            {'Go''Rust'},
            }
    for _, v1 := range pls {
        for _, v2 := range v1 {
            fmt.Printf('%s ', v2)
        }
        fmt.Printf('\n')
    }
}

在線運行程序

程序的輸出為,

C C++
JavaScript
Go Rust

內(nèi)存優(yōu)化

切片持有對底層數(shù)組的引用,。只要切片在內(nèi)存中,,數(shù)組就不能被垃圾回收。在內(nèi)存管理方面,,這是需要注意的,。讓我們假設我們有一個非常大的數(shù)組,我們只想處理它的一小部分,。然后,,我們由這個數(shù)組創(chuàng)建一個切片,并開始處理切片,。這里需要重點注意的是,,在切片引用時數(shù)組仍然存在內(nèi)存中。

一種解決方法是使用 copy 函數(shù) func copy(dst,,src[]T)int 來生成一個切片的副本,。這樣我們可以使用新的切片,原始數(shù)組可以被垃圾回收,。

package main

import (
    'fmt'
)

func countries() []string {
    countries := []string{'USA''Singapore''Germany''India''Australia'}
    neededCountries := countries[:len(countries)-2]
    countriesCpy := make([]stringlen(neededCountries))
    copy(countriesCpy, neededCountries) //copies neededCountries to countriesCpy
    return countriesCpy
}
func main() {
    countriesNeeded := countries()
    fmt.Println(countriesNeeded)
}

在線運行程序

在上述程序的第 9 行,,neededCountries := countries[:len(countries)-2 創(chuàng)建一個去掉尾部 2 個元素的切片 countries,在上述程序的 11 行,,將 neededCountries 復制到 countriesCpy 同時在函數(shù)的下一行返回 countriesCpy?,F(xiàn)在 countries 數(shù)組可以被垃圾回收, 因為 neededCountries 不再被引用,。

我已經(jīng)把我們迄今為止所討論的所有概念整理成一個程序。你可以從 github 下載它,。

這是數(shù)組和切片,。謝謝你的閱讀。請您留下寶貴的意見和意見,。

上一教程 - switch 語句

下一教程 - 可變函數(shù)


via: https:///arrays-and-slices/

作者:Nick Coghlan譯者:Dingo1991校對:Noluye polaris1119

本文由 GCTT 原創(chuàng)編譯,,Go 中文網(wǎng) 榮譽推出

參考資料

[1]

在線運行程序: https://play./p/Zvgh82u0ej

[2]

在線運行程序: https://play./p/WF0Uj8sv39

[3]

在線運行程序: https://play./p/NKOV04zgI6

[4]

在線運行程序: https://play./p/AdPH0kXRly

[5]

在線運行程序: https://play./p/_fVmr6KGDh

[6]

在線運行程序: https://play./p/kBdot3pXSB

[7]

在線運行程序: https://play./p/-ncGk1mqPd

[8]

在線運行程序: https://play./p/e3U75Q8eUZ

[9]

在線運行程序: https://play./p/UrIeNlS0RN

[10]

在線運行程序: https://play./p/80ejSTACO6

[11]

在線運行程序: https://play./p/Ji6FRon36m

[12]

在線運行程序: https://play./p/InchXI4yY8

[13]

https:///doc/effective_go.html#semicolons: https:///doc/effective_go.html#semicolons

[14]

在線運行程序: https://play./p/Za6w5eubBB

[15]

在線運行程序: https://play./p/_Z97MgXavA

[16]

在線運行程序: https://play./p/6FinudNf1k

[17]

在線運行程序: https://play./p/mdNi4cs854

[18]

在線運行程序: https://play./p/a1WOcdv827

[19]

程序: https://play./p/a1WOcdv827

[20]

在線運行程序: https://play./p/GcNzOOGicu

[21]

在線運行程序: https://play./p/M4OqxzerxN

[22]

可變函數(shù): https:///variadic-functions/

[23]

在線運行程序: https://play./p/VUSXCOs1CF

[24]

在線運行程序: https://play./p/x_-4XAJHbM

[25]

可變參數(shù)函數(shù): https:///variadic-functions/

[26]

在線運行程序: https://play./p/UnHOH_u6HS

[27]

在線運行程序: https://play./p/IzqDihNifq

[28]

程序: https://play./p/bWUb6R-1bS

[29]

在線運行程序: https://play./p/--p1AvNGwN

[30]

copy: https:///pkg/builtin/#copy

[31]

在線運行程序: https://play./p/35ayYBhcDE

[32]

github: https://github.com/golangbot/arraysandslices

[33]

可變函數(shù): https:///articles/12173

[34]

Nick Coghlan: https:///about/

[35]

Dingo1991: https://github.com/Dingo1991

[36]

Noluye: https://github.com/Noluye

[37]

polaris1119: https://github.com/polaris1119

[38]

GCTT: https://github.com/studygolang/GCTT

[39]

Go 中文網(wǎng): https:///



    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,,謹防詐騙,。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多