数组
同其他语言一样,数组是一些相同类型的元素的集合。数组声明
数组的类型为 n[T]
,其中 n
表示数组中元素的个数,T
表示数组中元素的类型。数组元素的个数 n
也是数组类型的一部分
package main import "fmt" func main() {
var a []int //int array a and length is 5
fmt.Println(a)
}
var a [5]int 是我们常用的一种声明数组的方式。同时也会给数组种的所有元素赋值int的初始值0.运行代码我们得到:[0 0 0 0 0] 我们还可以用shorhand 速记声明的方式声明和赋值数组:
package main import "fmt" func main() {
a := []int{, , , , } //int array a and length is 5
fmt.Println(a)
}
这个代码的运行结果是:[1 3 4 5 6]
如果没有给所有的元素赋值,那么后面的元素会被赋予默认值。
在声明数组的时候,可以使用...来代替数组长度,编译器会帮我们计算数组长度
package main import "fmt" func main() {
a := [...]int{, , } //int array a and length is 3
fmt.Println(len(a))
}
这个代码的运行结果是3,表明编译器帮我们计算好了数组长度。
由于数组的长度属于数组类型的一部分,那么[3]int和[5]int 不是相同一类型,不可以相互赋值。
数组遍历
Go提供了for rang来让我们遍历数组,这样比用for 循环简洁一些。
package main import "fmt" func main() {
a := [...]string{"a", "b"} for i, v := range a { //range returns both the index and value
fmt.Printf(" the element %d of a is %s \n", i, v)
}
}
上面的代码运行结果是:
the element 0 of a is a
the element 1 of a is b
切片
由于数组长度不可变,导致数组的应用场景大幅减少。还好Go给我们提供了切片。
把上面的代码稍微修改一下,我们来创建一个切片
package main import "fmt" func main() {
a := [...]string{"a", "b", "c", "d", "e"} for i, v := range a { //range returns both the index and value
fmt.Printf(" the element %d of a is %s \n", i, v)
} b := a[:]
fmt.Println(b)
}
运行结果是
the element of a is a
the element of a is b
the element of a is c
the element of a is d
the element of a is e
[c]
我们通过 a[start:end]
这样的语法创建了一个从 a[start]
到 a[end -1]
的切片。在上面代码中,我们用这种方式创建了长度为1 的切片b。
我们还可以使用和创建数组相似的方式来创建切片
package main import "fmt" func main() {
b := []string{"a", "b", "c", "d", "e"}
fmt.Println(b)
}
需要注意的是[]中间是没有长度或者...的。这段代码创建了一个切片b,然后代码的运行结果是:[a b c d e]
切片的长度和容量
切片的长度就是切片中元素的个数。切片的容量是 切片创建的数组的长度减去创建切片时的start值。
具体我们看代码
package main import "fmt" func main() {
a := [...]string{"a", "b", "c", "d", "e"}
b := a[:]
fmt.Printf("length of slice %d capacity %d", len(b), cap(b)) //length is 1 and capacity is 4 }
运行结果是:length of slice 1 capacity 4
append 追加数据到切片上
package main import "fmt" func main() {
a := [...]string{"a", "b", "c", "d", "e"}
b := a[:]
fmt.Printf("length of slice %d capacity %d\n", len(b), cap(b)) //length is 1 and capacity is 4
b = append(b, "x", "y", "z", "m", "n")
fmt.Printf("length of slice %d capacity %d\n", len(b), cap(b)) //length is 1 and capacity is 8 }
第8行代码给切片b追加了5个元素,那么长度就是6,长度超过了容量4,go是怎么做的?如果容量超了,go会创建一个新的数组,容量翻倍,然后返回新数组的完整切片。
代码的运行结果是
length of slice capacity
length of slice capacity
我们还可以使用append把一个切片完整的追加到一个切片上:
package main import "fmt" func main() {
a := []string{"a", "b"}
b := []string{"c", "d", "e"}
a = append(a, b...)
fmt.Println(a)
}
运行结果是:
[a b c d e]
这里有点类似ES6的写法
var arr = [1, 2, 3]; var arr1 = [...arr, 4, 5, 6];
切片是数组的一种外层表示,所以我们每次修改切片,最终都会将修改落到数组上。
但是这时候再修改切边,修改就不会再反应到原来的数组上。
make创建切片
我们还可以使用函数make来创建切片。func make([]T, len, cap) []T,其中cap参数是可选的。
package main import "fmt" func main() {
a := make([]int, )
fmt.Println(a) }
切片和数组作为参数传递
先上两段代码,第一段:
package main import "fmt" func main() {
a := []string{"a", "b", "c", "d", "e"}
fmt.Println("before call function:", a)
changeZeroElementA(a)
fmt.Println("after call function:", a) b := []string{"a", "b", "c", "d", "e"}
fmt.Println("before call function:", b)
changeZeroElementB(b)
fmt.Println("after call function:", b)
} func changeZeroElementA(arr []string) {
//arr = []string{"X", "Y"}
arr[] = "changed"
}
func changeZeroElementB(arr []string) {
arr[] = "changed"
}
结果是:
before call function: [a b c d e]
after call function: [changed b c d e]
before call function: [a b c d e]
after call function: [a b c d e]
第二段:
package main import "fmt" func main() {
a := []string{"a", "b", "c", "d", "e"}
fmt.Println("before call function:", a)
changeZeroElementA(a)
fmt.Println("after call function:", a) b := []string{"a", "b", "c", "d", "e"}
fmt.Println("before call function:", b)
changeZeroElementB(b)
fmt.Println("after call function:", b)
} func changeZeroElementA(arr []string) {
arr = []string{"X", "Y"}
arr[] = "changed"
}
func changeZeroElementB(arr []string) {
arr[] = "changed"
}
运行结果:
before call function: [a b c d e]
after call function: [a b c d e]
before call function: [a b c d e]
after call function: [a b c d e]
看到这里是不是有些奇怪,其实go里面一切都是值传递。这里有全方面的解释:https://*.com/questions/39993688/are-golang-slices-pass-by-value
切片是数组的一种外层表示,所以我们每次修改切片,最终都会将修改落到数组上。