go 语言教程(一):切片和数组
一:go语言数组
在go语言当中,数组定义有很多种方式,常用的如下所示:
package main
import "fmt"
//go 数组
func updateArray(s [5]int){
s[0] = 200
}
func main() {
var arr1 int//等价于 var arr1 [0]int
arr2 := [3]int{1,3,4}
arr3 := [...]int{1,3,45,677,889}//编译器自动推断数组大小
var grid [4][5]int//4行5列数组 [[0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]]
fmt.Println(arr1, arr2, arr3)
fmt.Println(grid)
for i,v := range arr3 {
fmt.Println(i, v)
}
fmt.Println("After update array")
updateArray(arr3)
//updateArray(arr1)//编译错误
fmt.Println(arr3)//[1 3 45 677 889]
}
在go语言当中,type [2]int 和type [5]int将会被看作是不同类型,所以上面updateArray(arr1)会报编译错误。同时,go语言当中对数组的传递是值传递,传递过程中是对原数组的拷贝,在updateArray方法中对数组的元素进行改变,是不会改变原数组的值得。因此,更多的用到的是切片(Slice)
二:go语言切片
切片的含义是数组的一个view(视图),对切片当中的元素进行更改的时候,能够直接映射到原数组。切片的使用如下:
package main
import "fmt"
//go语言当中array传递不能改变其值,而是拷贝,一般我们用切片
func updateSlice(s []int) {
s[0] = 100
}
func main(){
arr := [...]int{0,1,2,3,4,5,6,7}
fmt.Println("arr[2:6] = ", arr[2:6])
fmt.Println("arr[:6] = ", arr[:6])
s1 := arr[2:6]
fmt.Println("s1 = ", s1) //s1 = [2 3 4 5]
fmt.Println("arr[2:] = ", arr[2:])
fmt.Println("arr[:] = ", arr[:])
s2 := arr[:]
fmt.Println("s2 = ", s2)//s2 = [0 1 2 3 4 5 6 7]
fmt.Println("After update slice")
updateSlice(s1)
updateSlice(s2)
fmt.Println("after update slice then s1 = ", s1)//after update slice then s1 = [100 3 4 5]
fmt.Println("after update slice then s2 = ", s2)//after update slice then s2 = [100 1 100 3 4 5 6 7]
fmt.Println("the original array is arr = ", arr)//the original array is arr = [100 1 100 3 4 5 6 7]
fmt.Println("ReSlice")
s2 = s2[0:2]
fmt.Println(s2)
s2 = s2[0:1]
fmt.Println(s2)
}
在切片的使用当中,遵循的是包左不包右的原则,即arr[2,6]取得是arr的2,3,4,5下标的元素。在对Slice当中的元素进行改变的时候,会直接映射到原数组的元素,如上面After update slice之后,数组arr的arr[0]元素变为了100.同时,对于Slice还可以ReSlice,即slice还可以继续slice。
三:Slice的扩展
看如下代码:
package main
import "fmt"
//go语言当中array传递不能改变其值,而是拷贝,一般我们用切片
func updateSlice(s []int) {
s[0] = 100
}
func main(){
/*arr := [...]int{0,1,2,3,4,5,6,7}
fmt.Println("arr[2:6] = ", arr[2:6])
fmt.Println("arr[:6] = ", arr[:6])
s1 := arr[2:6]
fmt.Println("s1 = ", s1) //s1 = [2 3 4 5]
fmt.Println("arr[2:] = ", arr[2:])
fmt.Println("arr[:] = ", arr[:])
s2 := arr[:]
fmt.Println("s2 = ", s2)//s2 = [0 1 2 3 4 5 6 7]
fmt.Println("After update slice")
updateSlice(s1)
updateSlice(s2)
fmt.Println("after update slice then s1 = ", s1)//after update slice then s1 = [100 3 4 5]
fmt.Println("after update slice then s2 = ", s2)//after update slice then s2 = [100 1 100 3 4 5 6 7]
fmt.Println("the original array is arr = ", arr)//the original array is arr = [100 1 100 3 4 5 6 7]
fmt.Println("ReSlice")
s2 = s2[0:2]
fmt.Println(s2)
s2 = s2[0:1]
fmt.Println(s2)*/
arr := [...]int{0,1,2,3,4,5,6,7}
s1 := arr[2:6]
s2 := s1[3:5]
fmt.Println("extending slice")
fmt.Println("s1 = ",s1)//s1 = [2 3 4 5]
fmt.Println("s2 = ",s2)//s2 = [5 6]
}
很神奇的现象是s2等于[5,6],但是s1当中却不应该有6这个元素的值的,s1也没有4这个下标索引的,但是s2却取到了,这是为什么呢?
从上图可以看出,每一个slice实际上是保留了指向原数组的下标的,但是这在切片当中的索引是不可见的,例如,取s1[4]就会报错:index of range 。因此,切片是有下面几个特性的:
1. Slice可以向后扩展,不可以向前扩展。
2. s[i]不可以超越len(s),向后扩展不可以超越底层数组cap(s)
那么,不妨打印一下Slice的len和cap来看一下结果:
package main
import "fmt"
//go语言当中array传递不能改变其值,而是拷贝,一般我们用切片
func updateSlice(s []int) {
s[0] = 100
}
func main(){
/*arr := [...]int{0,1,2,3,4,5,6,7}
fmt.Println("arr[2:6] = ", arr[2:6])
fmt.Println("arr[:6] = ", arr[:6])
s1 := arr[2:6]
fmt.Println("s1 = ", s1) //s1 = [2 3 4 5]
fmt.Println("arr[2:] = ", arr[2:])
fmt.Println("arr[:] = ", arr[:])
s2 := arr[:]
fmt.Println("s2 = ", s2)//s2 = [0 1 2 3 4 5 6 7]
fmt.Println("After update slice")
updateSlice(s1)
updateSlice(s2)
fmt.Println("after update slice then s1 = ", s1)//after update slice then s1 = [100 3 4 5]
fmt.Println("after update slice then s2 = ", s2)//after update slice then s2 = [100 1 100 3 4 5 6 7]
fmt.Println("the original array is arr = ", arr)//the original array is arr = [100 1 100 3 4 5 6 7]
fmt.Println("ReSlice")
s2 = s2[0:2]
fmt.Println(s2)
s2 = s2[0:1]
fmt.Println(s2)*/
arr := [...]int{0,1,2,3,4,5,6,7}
s1 := arr[2:6]
s2 := s1[3:5]
fmt.Println("extending slice")
fmt.Printf("s1 = %v, len(s1) = %d, cap(s1) = %d\n ",s1, len(s1), cap(s1))//s1 = [2 3 4 5], len(s1) = 4, cap(s1) = 6
fmt.Printf("s2 = %v, len(s2) = %d, cap(s2) = %d\n ",s2, len(s2), cap(s2))//s2 = [5 6], len(s2) = 2, cap(s2) = 3
}
可以看见cap(s1)的值是6,cap(s2)的值是3。
四: Slice的操作
代码如下:
package main
import "fmt"
//Slice的操作
/*
author: lory
*/
func main() {
arr := [...]int{0,1,2,3,4,5,6,7}
s1 := arr[2:6]
s2 := s1[3:5]
s3 := append(s2,10)
s4 := append(s3,11)
s5 := append(s4,12)
fmt.Println("s3, s4, s5 = ", s3, s4, s5)//s3, s4, s5 = [5 6 10] [5 6 10 11] [5 6 10 11 12]
fmt.Println(arr)//[0 1 2 3 4 5 6 10]
}
s3,s4,s5的值没什么好奇怪的,但是arr的值只有最后一个变为了10,那是因为s2的cap是3,因此在append(s2,10)的时候arr的最后一位变为了10,又因为数组的长度是固定的,因此,在继续append的时候,go语言会对数组都进行一份拷贝为更大的数组,也就是说,s4,s5不在是对arr的view(视图)了。同时,由于append方法可能会改变数组的len和cap。得出结论是:
1.添加元素时如果超越cap,系统会重新分配更大的底层数组。
2.由于值传递的关系,必须接收append的返回值。s = append(slice, val)
其他的slice操作:
package main
import "fmt"
//Slice的操作
/*
author: lory
*/
func main() {
fmt.Println("creating slice")
var s []int
for i := 0; i<100 ; i++ {
printSlice(s)
//1.create slice
s = append(s, 2 * i +1)
}
fmt.Println(s)
//2. create slice
s1 := []int{2,4,6,8}
printSlice(s1)
//3.create slice with len
s2 := make([]int, 16)
printSlice(s2)
//4. create slice with len and cap
s3 := make([]int, 12, 32)
printSlice(s3)
fmt.Println("Copying slice")
copy(s2, s1)
printSlice(s2)
fmt.Println("Deleting element from slice")
s2 = append(s2[:3], s2[4:]...)
printSlice(s2)
fmt.Println("Poping from front")
front := s2[0]
s2 = s2[1:]
fmt.Println(front)
printSlice(s2)
fmt.Println("Poping from back")
tail := s2[len(s2) -1]
s2 = s2[:len(s2)-1]
fmt.Println(tail)
printSlice(s2)
}
func printSlice(s []int) {
fmt.Printf("%v,len= %d, cap= %d\n", s, len(s), cap(s))
}
下一篇: 关于clear和浮动