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

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值