1.Go语言的静态数组和动态数组slice
Go语言支持两种数组,分别为静态和动态数组,我们同样用例子来感受这两种数组的用法
1.1 静态数组
我们先给出一个静态数组的声明方式
package main
import "fmt"
func main() {
// 声明一个静态数组array1,长度为10,默认前三个元素元素为1,2,3,其余为0
array1 := [10]int{1, 2, 3}
fmt.Println(array1)
}
运行结果
[1 2 3 0 0 0 0 0 0 0]
可以看到,Go语言中的数组的定义方式于java类似,且支持提供部分默认值的形式。静态数组的特点即为长度固定,声明时即开辟连续空间地址来存放数组,不可延长数组的长度
1.2 动态数组slice
熟悉python的列表或者java ArrayList类的小伙伴可能对这个并不陌生,因为slice和这两种类型很类似,Go语言的动态数组slice也被成为切片,所谓动态,即可以动态的添加元素,动态的分配内存地址。且在传参的时候,传递的是地址而不是值拷贝。
package main
import "fmt"
func printArray(slice1 []int) {
// 不需要索引值,只需要每个元素的值
for _,value := range slice1 {
fmt.Println( "value=", value)
}
}
func main() {
// 声明一个动态数组slice1,给了三个默认值1,2,3
slice1 := []int{1, 2, 3}
printArray(slice1)
}
运行结果
value= 1
value= 2
value= 3
以上是slice的简单用法,我们看看如果在函数中改变其中元素的值,动态数组和静态数组的区别:
package main
import "fmt"
func testArray(array1 [10]int) {
//改变其中一个元素的值
array1[1] = 20
}
func testSlice(slice1 []int) {
//改变其中一个元素的值
slice1[1] = 20
}
func main() {
// 声明一个长度为10的静态数组array1,给了三个默认值1,2,3
array1 := [10]int{1, 2, 3}
// 声明一个动态数组slice1,给了三个默认值1,2,3
slice1 := []int{1, 2, 3}
fmt.Println("before..........")
fmt.Println(array1)
fmt.Println(slice1)
testArray(array1)
testSlice(slice1)
fmt.Println("after...........")
fmt.Println(array1)
fmt.Println(slice1)
}
运行结果:
before..........
[1 2 3 0 0 0 0 0 0 0]
[1 2 3]
after...........
[1 2 3 0 0 0 0 0 0 0]
[1 20 3]
可以看到,两个方法都尝试改变数组中第二个元素的值,但是我们可以看到,静态数组的值并没有发生变化,这是因为在传参的时候才用的值传递,传递过去的array1只是main中array1的副本,而动态数组slice1传递的是地址,也可以说是指向sclice内存地址的指针。所以传递过去后读其中值的修改在在回到mian函数中是有效的。
3.数组的遍历方式
package main
import "fmt"
func printArray(array [10]int) {
for index,value := range array {
fmt.Println("index:", index, "value=", value)
}
}
func main() {
// 声明一个静态数组array1,长度为10,默认前三个元素元素为1,2,3,其余为0
array1 := [10]int{1, 2, 3}
printArray(array1)
}
运行结果:
index: 0 value= 1
index: 1 value= 2
index: 2 value= 3
index: 3 value= 0
index: 4 value= 0
index: 5 value= 0
index: 6 value= 0
index: 7 value= 0
index: 8 value= 0
index: 9 value= 0
在遍历数组的时候,会有两个返回值,分别是数组对应元素的索引和对应位置的值,有时候不需要数组的索引信息的时候,可以采用匿名的方式,这个与python十分相似。
package main
import "fmt"
func printArray(array [10]int) {
// 不需要索引值,只需要每个元素的值
for _,value := range array {
fmt.Println( "value=", value)
}
}
func main() {
// 声明一个静态数组array1,长度为10,默认前三个元素元素为1,2,3,其余为0
array1 := [10]int{1, 2, 3}
printArray(array1)
}
运行结果:
value= 1
value= 2
value= 3
value= 0
value= 0
value= 0
value= 0
value= 0
value= 0
value= 0
对于动态数组,即切片的遍历方式与数组相同,这里不再演示。
值得注意的是,不同长度的静态数组代表的是不同类型。这里我们可以通过数组传参来感受
package main
import "fmt"
func printArray(array [20]int) {
// 不需要索引值,只需要每个元素的值
for _,value := range array {
fmt.Println( "value=", value)
}
}
func main() {
// 声明一个静态数组array1,长度为10,默认前三个元素元素为1,2,3,其余为0
array1 := [10]int{1, 2, 3}
printArray(array1)
}
程序会报错,报错信息为
cannot use array1 (type [10]int) as type [20]int in argument to printArray
可以看到,长度为20的静态数组和长度为10的静态数组是完全不同的数据类型,不能兼容。
Go语言的切片还有很多声明方式,这里再列举一些。
首先,slice在声明的时候如果不给定一些默认值,那可其长度就为0,且为空
package main
import "fmt"
func main() {
// 声明一个动态数组slice1,
var slice1 []int
fmt.Println(len(slice1))
fmt.Println(slice1)
}
运行结果:
0
[]
其次,也可以让系统预开辟一些空间,比如需要一个长度为3的slice
package main
import "fmt"
func main() {
// 声明一个动态数组slice1,
slice1 := make([]int, 3)
fmt.Println(len(slice1))
fmt.Println(slice1)
}
运行结果:
3
[0 0 0]
这里使用make来创建了一个长度为3的slice,系统默认给每个值赋值为0,这里可能有小伙伴会混淆什么时候用var好,什么时候:=好,个人认为是只声明不赋值的情况下采用var,声明并赋值的话采用:=。
对于slice的其他用法,如添加元素和删除元素,将在下一节提到。