# Go教程第八篇：Array和Slice

Tesfaye · · 161 次点击 · · 开始浏览

# Array和Slice

## Array

### 数组声明

[n]T
n表明了数组元素的个数，T表明的是元素的数据类型。另外，元素个数n也是类型的一部分(这点我们会在稍后讲解)。Go提供了多种声明数组的方式，我们来一个个看下。

``````package main

import (
"fmt"
)

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

``````

var a[3]int 包含了一个含有3个整数的数组。数组中的所有元素的值都会自动地被初始化该数组类型所对应的零值zero value。在本例中，a是一个整型数组，因此a的所有元素都会被初始化为0值，0即int类型的零值。运行上面的程序，得到的输出结果是： [0 0 0]

``````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)
}

``````

``````package main
import (
"fmt"
)
func main() {
a := [3]int{12, 78, 50} // short hand declaration to create array
fmt.Println(a)
}
``````

``````package main

import (
"fmt"
)

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

``````package main
import (
"fmt"
)

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

``````

``````package main

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

``````

### 数组是值类型

Go里面的数组是值类型而非引用类型，这意味着，当他们被赋值给一个新变量的时候，会把原始的数组拷贝给新变量。如果对新变量做出修改，不会影响到原来的数组。

``````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)
}

``````

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

``````

``````package main

import "fmt"

func changeLocal(num [5]int) {
num[0] = 55
fmt.Println("inside function ", num)

}
func main() {
num := [...]int{5, 6, 7, 8, 8}
fmt.Println("before passing to function ", num)
changeLocal(num) //num is passed by value
fmt.Println("after passing to function ", num)
}

``````

``````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]

``````

### 数组长度

``````package main

import "fmt"

func main() {
a := [...]float64{67.7, 89.8, 21, 78}
fmt.Println("length of a is",len(a))

}

``````

### 使用角标遍历数组

for循环可用于遍历数组：

``````package main

import "fmt"

func main() {
a := [...]float64{67.7, 89.8, 21, 78}
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])
}
}

``````

``````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提供了一个更好更简洁的方式迭代数组，那就是使用range。range会把角标和元素都返回来。我们来用range重写上面的代码，计算出所有元素之和：

``````package main

import "fmt"

func main() {
a := [...]float64{67.7, 89.8, 21, 78}
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)
}

``````

``````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

``````

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

``````

### 多维数组

``````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[2][0] = "AT&T"
b[2][1] = "T-Mobile"
fmt.Printf("\n")
printarray(b)
}

``````

``````lion tiger
cat dog
pigeon peacock

apple samsung
AT&T T-Mobile

``````

## Slice

slice是在数组基础上构建出来的一个方便的、灵活的、强大的包装类。slice本身不存储任何数据，他们仅仅是对已有数组的引用。

### 创建一个分片

[]T

T是slice的元素类型。

``````package main

import (
"fmt"
)

func main() {
a := [5]int{76, 77, 78, 79, 80}
var b []int = a[1:4] //creates a slice from a[1] to a[3]
fmt.Println(b)
}

``````

a[start:end]这个语法，会从数组a的角标start到end-1里创建一个slice。因此，在上述程序

[77,78,79]。

``````package main

import (
"fmt"
)

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

``````

### 修改slice

slice自己并不存储数据。它仅仅是底层数组的一个表示。对slice的任何修改都会影响到底层的数组。

``````package main

import (
"fmt"
)

func main() {
darr := [...]int{57, 89, 90, 82, 100, 78, 67, 69, 59}
dslice := darr[2:5]
fmt.Println("array before",darr)
for i := range dslice {
dslice[i]++
}
fmt.Println("array after",darr)
}
``````

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

``````

``````package main

import (
"fmt"
)

func main() {
numa := [3]int{78, 79 ,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)
}

``````

``````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]

``````

#### slice的长度和容量

slice的长度是其中的元素个数。slice的容量为其底层数组从slice的开始脚标开始一直到数组最后一个脚本为止的所有元素个数。

``````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 fruitslice is 2 and capacity is 6
}

``````

fruitarray的长度是7。因为fruitslice是从脚标1开始处创建，所以fruitslice的容量即是从fruitarray中除去第一个元素之外的所有，本例中，即是： 从"orange"开始，一直到"chikoo"。所以fruitslice的容量为：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))
}

``````

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

``````

### 使用make创建slice

func make([]T,len,cap) 可以用来创建slice，接收三个参数： type, length,capacity。
capacity参数是可选的，如果不传的话，默认值为数组长度。make函数会创建一个array，并返回

``````package main

import (
"fmt"
)

func main() {
i := make([]int, 5, 5)
fmt.Println(i)
}

``````

### 向slice中添加内容

append的函数定义是：func append(s []T, x ...T) []T。

X...T表示的是： 该函数可以接收多个参数X。这种类型的函数被称为：可变函数。

``````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: [Ferrari Honda Ford] has old length 3 and capacity 3
cars: [Ferrari Honda Ford Toyota] has new length 4 and capacity 6

``````

slice 类型的零值是nil。值为nil的slice其长度和容量都是0。我们可以向值为nil的slice中追加元素：

``````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)
}
}

``````

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

``````

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

``````

food: [potatoes tomatoes brinjal oranges apples]

### slice作为参数传递

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

``````

slice含有三个部分： 长度、容量、指向零值元素的数组。当把一个slice传递给函数之后，虽然它是值传递，但是指针变量将指向同一个底层数组。因此当slice作为参数传递给函数之后，在函数内部对此slice做出的修改，在此函数的外部也是可见的。我们可以写个程序检查一下：

``````package main

import (
"fmt"
)

func subtactOne(numbers []int) {
for i := range numbers {
numbers[i] -= 2
}

}
func main() {
nos := []int{8, 7, 6}
fmt.Println("slice before function call", nos)
subtactOne(nos)                               //function modifies the slice
fmt.Println("slice after function call", nos) //modifications are visible outside
}

``````

``````slice before function call [8 7 6]
slice after function call [6 5 4]

``````

### 多维slice

``````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

``````

### 内存优化

``````package main

import (
"fmt"
)

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

``````

## 致谢

0 回复

• 请尽量让自己的回复能够对别人有帮助
• 支持 Markdown 格式, **粗体**、~~删除线~~、``单行代码``
• 支持 @ 本站用户；支持表情（输入 : 提示），见 Emoji cheat sheet
• 图片支持拖拽、截图粘贴等方式上传

# Array和Slice

## Array

### 数组声明

[n]T
n表明了数组元素的个数，T表明的是元素的数据类型。另外，元素个数n也是类型的一部分(这点我们会在稍后讲解)。Go提供了多种声明数组的方式，我们来一个个看下。

``````package main

import (
"fmt"
)

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

``````

var a[3]int 包含了一个含有3个整数的数组。数组中的所有元素的值都会自动地被初始化该数组类型所对应的零值zero value。在本例中，a是一个整型数组，因此a的所有元素都会被初始化为0值，0即int类型的零值。运行上面的程序，得到的输出结果是： [0 0 0]

``````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)
}

``````

``````package main
import (
"fmt"
)
func main() {
a := [3]int{12, 78, 50} // short hand declaration to create array
fmt.Println(a)
}
``````

``````package main

import (
"fmt"
)

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

``````package main
import (
"fmt"
)

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

``````

``````package main

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

``````

### 数组是值类型

Go里面的数组是值类型而非引用类型，这意味着，当他们被赋值给一个新变量的时候，会把原始的数组拷贝给新变量。如果对新变量做出修改，不会影响到原来的数组。

``````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)
}

``````

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

``````

``````package main

import "fmt"

func changeLocal(num [5]int) {
num[0] = 55
fmt.Println("inside function ", num)

}
func main() {
num := [...]int{5, 6, 7, 8, 8}
fmt.Println("before passing to function ", num)
changeLocal(num) //num is passed by value
fmt.Println("after passing to function ", num)
}

``````

``````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]

``````

### 数组长度

``````package main

import "fmt"

func main() {
a := [...]float64{67.7, 89.8, 21, 78}
fmt.Println("length of a is",len(a))

}

``````

### 使用角标遍历数组

for循环可用于遍历数组：

``````package main

import "fmt"

func main() {
a := [...]float64{67.7, 89.8, 21, 78}
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])
}
}

``````

``````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提供了一个更好更简洁的方式迭代数组，那就是使用range。range会把角标和元素都返回来。我们来用range重写上面的代码，计算出所有元素之和：

``````package main

import "fmt"

func main() {
a := [...]float64{67.7, 89.8, 21, 78}
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)
}

``````

``````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

``````

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

``````

### 多维数组

``````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[2][0] = "AT&T"
b[2][1] = "T-Mobile"
fmt.Printf("\n")
printarray(b)
}

``````

``````lion tiger
cat dog
pigeon peacock

apple samsung
AT&T T-Mobile

``````

## Slice

slice是在数组基础上构建出来的一个方便的、灵活的、强大的包装类。slice本身不存储任何数据，他们仅仅是对已有数组的引用。

### 创建一个分片

[]T

T是slice的元素类型。

``````package main

import (
"fmt"
)

func main() {
a := [5]int{76, 77, 78, 79, 80}
var b []int = a[1:4] //creates a slice from a[1] to a[3]
fmt.Println(b)
}

``````

a[start:end]这个语法，会从数组a的角标start到end-1里创建一个slice。因此，在上述程序

[77,78,79]。

``````package main

import (
"fmt"
)

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

``````

### 修改slice

slice自己并不存储数据。它仅仅是底层数组的一个表示。对slice的任何修改都会影响到底层的数组。

``````package main

import (
"fmt"
)

func main() {
darr := [...]int{57, 89, 90, 82, 100, 78, 67, 69, 59}
dslice := darr[2:5]
fmt.Println("array before",darr)
for i := range dslice {
dslice[i]++
}
fmt.Println("array after",darr)
}
``````

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

``````

``````package main

import (
"fmt"
)

func main() {
numa := [3]int{78, 79 ,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)
}

``````

``````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]

``````

#### slice的长度和容量

slice的长度是其中的元素个数。slice的容量为其底层数组从slice的开始脚标开始一直到数组最后一个脚本为止的所有元素个数。

``````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 fruitslice is 2 and capacity is 6
}

``````

fruitarray的长度是7。因为fruitslice是从脚标1开始处创建，所以fruitslice的容量即是从fruitarray中除去第一个元素之外的所有，本例中，即是： 从"orange"开始，一直到"chikoo"。所以fruitslice的容量为：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))
}

``````

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

``````

### 使用make创建slice

func make([]T,len,cap) 可以用来创建slice，接收三个参数： type, length,capacity。
capacity参数是可选的，如果不传的话，默认值为数组长度。make函数会创建一个array，并返回

``````package main

import (
"fmt"
)

func main() {
i := make([]int, 5, 5)
fmt.Println(i)
}

``````

### 向slice中添加内容

append的函数定义是：func append(s []T, x ...T) []T。

X...T表示的是： 该函数可以接收多个参数X。这种类型的函数被称为：可变函数。

``````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: [Ferrari Honda Ford] has old length 3 and capacity 3
cars: [Ferrari Honda Ford Toyota] has new length 4 and capacity 6

``````

slice 类型的零值是nil。值为nil的slice其长度和容量都是0。我们可以向值为nil的slice中追加元素：

``````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)
}
}

``````

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

``````

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

``````

food: [potatoes tomatoes brinjal oranges apples]

### slice作为参数传递

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

``````

slice含有三个部分： 长度、容量、指向零值元素的数组。当把一个slice传递给函数之后，虽然它是值传递，但是指针变量将指向同一个底层数组。因此当slice作为参数传递给函数之后，在函数内部对此slice做出的修改，在此函数的外部也是可见的。我们可以写个程序检查一下：

``````package main

import (
"fmt"
)

func subtactOne(numbers []int) {
for i := range numbers {
numbers[i] -= 2
}

}
func main() {
nos := []int{8, 7, 6}
fmt.Println("slice before function call", nos)
subtactOne(nos)                               //function modifies the slice
fmt.Println("slice after function call", nos) //modifications are visible outside
}

``````

``````slice before function call [8 7 6]
slice after function call [6 5 4]

``````

### 多维slice

``````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

``````

### 内存优化

``````package main

import (
"fmt"
)

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

``````