cafebabe go入门练习004:数组和切片

数组

数组是固定长度的特定类型元素的序列。数组的大小是数组定义的一部分,所以两个大小不同的数组是两个不同的类型,当然也不能比较。

数组的定义方式:

func main() {
	var a [3]int
	b := [3]int{1, 2, 3}
	c := [...]int{1, 2, 3}
	d := [...]int{1: 2, 0: 1, 2: 3}

	fmt.Println(a)
	fmt.Println(b)
	fmt.Println(c)
	fmt.Println(d)
}

go中函数传参一般都是值传递的,数组传参也是如此。如果确实要达到引用传递(pass arrays by reference)的效果,必须定义参数类型为指针。更好的方式是使用切片。

切片

go中数组使用很不灵活,因此需要一种灵活访问数组子序列的数据结构,这便是切片。

切片由三部分组成:

  • data: 指针,切片起始位置指向的底层数组元素,并不一定是数组的第一个元素;
  • length:切片大小
  • capacity:切片容量,data指向的底层数组元素到最后一个元素。显然length<=capacity

切片和数组的关系如图:

所以,可以通过切片达到修改数组的目的,如反转数组元素:

// reverse reverses a slice of ints in place.
func reverse(s []int) {
      for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
            s[i], s[j] = s[j], s[i]
      }
}

切片一般从底层序列定义而来,作为独立的数据结构,当然也可以直接定义:

func main() {
	var a []int
	fmt.Printf("a==nil:%t\tlen=%d\tcap=%d\n", a == nil, len(a), cap(a))
	b := []int(nil)
	fmt.Printf("b==nil:%t\tlen=%d\tcap=%d\n", b == nil, len(b), cap(b))
	c := []int{}
	fmt.Printf("c==nil:%t\tlen=%d\tcap=%d\n", c == nil, len(c), cap(c))
	d := make([]int, 0, 0)
	fmt.Printf("d==nil:%t\tlen=%d\tcap=%d\n", d == nil, len(d), cap(d))
}

输出如下:所以切片的零值是nil,但依然可以访问它,go确实更安全。

模拟append函数:

//append y to slice x
func appendInt(x []int, y int) []int {
	var z []int
	zlen := len(x) + 1
	if zlen < cap(x) {
		//空间够,z直接从x扩展来
		z = x[:zlen]
	} else {
		//扩容,2倍速增长
		zcap := zlen
		if zcap < 2*len(x) {
			zcap = 2 * len(x)
		}
		z = make([]int, zlen, zcap)
		copy(z, x)
	}
	z[len(x)] = y
	return z
}

slice实现栈

stack = append(stack, v) // push v
top := stack[len(stack)-1] // top of stack
stack = stack[:len(stack)-1] // pop

slice删除中间位置

func remove(slice []int, i int) []int {
      copy(slice[i:], slice[i+1:])
      return slice[:len(slice)-1]
}

posted on 2020-10-23 09:22  caffebabe  阅读(55)  评论(0编辑  收藏  举报