Go 数组与切片

发布时间: 更新时间: 总字数:2141 阅读时间:5m 作者: 分享 复制网址

Golang数组与切片使用介绍,通过示例演示Golang语言中如何使用数组、切片,以及介绍数组与切片异同,最后介绍排序模块。

数组

数组是具有相同数据类型的数据项,组成的长度固定的序列,数据项叫做数组的元素,数组的长度必须为非负整数常量,数组长度是类型的一部分。

声明

声明数组时需要指定数组元素的类型和数量,数组声明后长度不可修改,每个数据项的初始值为对应数据类型的零值。 格式:

var <变量名> [长度]<类型>

// 短声明
<变量名> := [长度]<类型>{}

说明:

  • 长度可以使用 ... 自动计算数组长度

  • 获取数组的长度:len(<数组变量名>)

  • 示例

package main

import "fmt"

func main() {
	var names [5]string
	var ages [5]int
	var isBoy [5]bool

	fmt.Printf("%T, %T\n", names, ages) // [5]string, [5]int
	fmt.Printf("%q\n", names)
	fmt.Println(ages)
	fmt.Println(isBoy)
}

输出为:

[5]string, [5]int
["" "" "" "" ""]
[0 0 0 0 0]
[false false false false false]

赋值

为新声明的数组赋字面量值

package main

import "fmt"

func main() {
	// 指定字面量的长度
	var ages = [5]int{5, 7, 4: 6}
	fmt.Println(ages) // [5 7 0 0 6]

	var names = [5]string{0: "xiaoming", 4: "xiaowang"}
	fmt.Printf("%q\n", names) // ["xiaoming" "" "" "" "xiaowang"]

	// 自动推到长度
	var isBoy = [...]bool{true, false, true, false, true}
	fmt.Println(isBoy, len(isBoy)) // [true false true false true] 5
}

关系运算

package main

import "fmt"

func main() {
	nums1 := [5]int{5, 7}
	nums2 := [5]int{5, 7}
	nums3 := [5]int{5, 8}
	fmt.Println(nums1 == nums2) // true
	fmt.Println(nums1 == nums3) // false

	//nums4 := [...]int{5, 8, 2}
	//fmt.Println(nums1 == nums4) // Invalid operation: nums1 == nums4 (mismatched types [5]int and [3]int)
}

索引

数组的索引值:0,1,2,…,len(array)-1

range 获取数组的 indexvalueindex 的值可以使用空白标识符 _ 接受

package main

import "fmt"

func main() {
	nums1 := [5]int{5, 7}
	nums1[0] = 8
	fmt.Println(nums1[0], nums1[len(nums1)-1]) // 8 0
}
  • 访问并修改索引的值
package main

import "fmt"

func ExampleArray() {
	nums1 := [5]int{5, 7}
	for i := 0; i < len(nums1); i++ {
		fmt.Println(nums1[i])
	}
	for index, num := range nums1 {
		fmt.Println(index, num)
		nums1[index] += 1
	}
	fmt.Println(nums1)

	// Output:
	//5
	//7
	//0
	//0
	//0
	//0 5
	//1 7
	//2 0
	//3 0
	//4 0
	//[6 8 1 1 1]
}

多维数组

多维数组不使用 ... 定义可变长度

  // 定义长度为3,每个元素是长度为2的int数组
	var mularray [3][2]int
	fmt.Printf("%T, %v\n", mularray, mularray)

	// Output:
	//[3][2]int, [[0 0] [0 0] [0 0]]

	mularray := [3][2]int{{1, 2}}
	fmt.Printf("%T, %v\n", mularray, mularray)

	// Output:
	//[3][2]int, [[1 2] [0 0] [0 0]]

切片

切片是长度可变的数组,组成包括:

  • 指针:指向切片第一个元素指向的数组数组元素的地址
  • 长度:切片元素的数量,可使用方法 len() 获取
  • 容量:切片开始到结束位置元素的数量,可使用方法 cap() 获取

定义:

// 初始化
[]type{v1, v2, ...}

// 空切片
[]type{}

// 指定长度和容量
[]type{index_x:v1, index_y:v2, ...}

// make 函数初始化
make([]type, len)
make([]type, len, cap)  // len<=cap

// 数组切片
array[start:end]
array[start:end:cap]
array[start:]
array[:end]

说明:

  • start、end 是整数,且 start<=end && end <= len(array)-1
  • 切片的类型是切片,如 int 数组的切片是数组 []int
  • 如果省略 start、end,值为整个数组的所有元素
  • cap 切片的容量,且 cap <= len(array)-1
  • nil 切片 []int VS 空切片 []int{}
  • 相关函数:
    • 获取长度:len()
    • 获取容量:cap()
    • 追加元素:append()
    • 复制:copy()

切片声明后,初始化值为 nil,表示暂不存在切片

示例

package main

import "fmt"

func ExampleSlice() {
	str := "abcdefg"
	fmt.Printf("%T, %v\n", str[1:5], str[1:5])

	nums := []int{1, 2, 3, 4, 5, 6, 7, 8}
	fmt.Printf("%T, %T, %v\n", nums, nums[1:5], nums[1:5])

	// Output:
	//string, bcde
	//[]int, []int, [2 3 4 5]
}

示例2

package main

import "fmt"

func ExampleSlice() {
	// 声明切片
	var nums []int
	fmt.Printf("%T\n", nums)
	fmt.Printf("%#v %d %d\n", nums, len(nums), len(nums))
	fmt.Println(nums == nil) // 指针,指向 nil

	// 声明数组
	var ages = [3]int{1, 2, 3}
	fmt.Printf("%T\n", ages)
	fmt.Printf("%#v\n", ages)
	//fmt.Println(ages == nil) // Cannot convert 'nil' to type '[3]int'

	// 字面量
	nums = []int{1, 2, 3}
	fmt.Printf("%#v %d %d\n", nums, len(nums), len(nums))
	nums = []int{1, 2, 3, 4}
	fmt.Printf("%#v %d %d\n", nums, len(nums), len(nums))

	// 数组切片赋值
	array := [5]int{1, 2, 3, 4, 5}
	nums = array[0:3]
	fmt.Printf("%#v %d %d\n", nums, len(nums), len(nums))

	// Output:
	//[]int
	//[]int(nil) 0 0
	//true
	//[3]int
	//[3]int{1, 2, 3}
	//[]int{1, 2, 3} 3 3
	//[]int{1, 2, 3, 4} 4 4
	//[]int{1, 2, 3} 3 3
}

make 初始化

package main

import "fmt"

func ExampleSlice() {
	// make 函数,对指针进行初始化
	//nums := make([]int, 3, 3)
	nums := make([]int, 3)
	fmt.Printf("%#v %d %d\n", nums, len(nums), cap(nums))

	nums = make([]int, 3, 5)
	fmt.Printf("%#v %d %d", nums, len(nums), cap(nums))

	// Output:
	//[]int{0, 0, 0} 3 3
	//[]int{0, 0, 0} 3 5
}

操作

  • append 操作容空间容量不足,会重新申请内存空间
package main

import "fmt"

func ExampleSlice() {
	// make 函数,对指针进行初始化
	//nums := make([]int, 3, 3)
	nums := make([]int, 3, 4)
	fmt.Printf("%#v %d %d\n", nums, len(nums), cap(nums))

	// 修改值
	fmt.Println(nums[0])
	nums[0] = 8
	fmt.Println(nums)

	// 增加元素
	nums = append(nums, 6)
	fmt.Printf("%#v %d %d\n", nums, len(nums), cap(nums))

	nums = append(nums, 8) // append 后,cap 由 4 增长到 8,若切片放不下,重新申请空间,容量增长一般是之前的1倍,因此需要 = 重新赋值
	fmt.Printf("%#v %d %d\n", nums, len(nums), cap(nums))

	// 切片操作,获取的仍然是一个切片
	fmt.Printf("%T %#v\n", nums[0:2], nums[0:2])

	// cap 计算,新切片的容量为 new_cap - start = 4,不指定 cap 时,为 org_cap - start = 1,且 new_cap 不能比原来大
	nums2 := nums[1:2:5]
	fmt.Printf("%T %#v %d %d\n", nums2, nums2, len(nums2), cap(nums2))
	nums2 = nums[1:2]
	fmt.Printf("%T %#v %d %d\n", nums2, nums2, len(nums2), cap(nums2))

	// Output:
	//[]int{0, 0, 0} 3 4
	//0
	//[8 0 0]
	//[]int{8, 0, 0, 6} 4 4
	//[]int{8, 0, 0, 6, 8} 5 8
	//[]int []int{8, 0}
	//[]int []int{0} 1 4
	//[]int []int{0} 1 7
}

复制

与两个数组的长度有关

package main

import "fmt"

func ExampleSlice() {
	nums1 := []int{1, 2, 3}
	nums2 := []int{10, 20, 30, 40}
	copy(nums2, nums1) // 仅覆盖nums2的前3个元素
	fmt.Println(nums1, nums2)

	nums1 = []int{1, 2, 3}
	nums2 = []int{10, 20, 30, 40}
	copy(nums1, nums2) // 仅覆盖nums1的前3个元素
	fmt.Println(nums1, nums2)

	// Output:
	//[1 2 3] [1 2 3 40]
	//[10 20 30] [10 20 30 40]
}

切片元素的删除

package main

import "fmt"

func ExampleSlice() {
	nums := []int{10, 20, 30, 40}
	fmt.Println(nums[1:])
	fmt.Println(nums[:len(nums)-1])

	// 删除第3个元素 30
	// 通过可变参数,num[3:]... 表示 unpack slice nums[3:]
	fmt.Println(append(nums[:2], nums[3:]...))

	// 通过 copy
	copy(nums[2:], nums[3:])
	fmt.Println(nums)
	fmt.Println(nums[:len(nums)-1])

	// Output:
	//[20 30 40]
	//[10 20 30]
	//[10 20 40]
	//[10 20 40 40]
	//[10 20 40]
}

切片共用地址导致的问题

package main

import "fmt"

func ExampleSlice() {
	// 共用地址导致的问题
	nums := make([]int, 3, 5)
	fmt.Printf("%#v %d %d\n", nums, len(nums), cap(nums))
	nums1 := nums[1:3]
	fmt.Println(nums, nums1)

	nums1[0] = 8
	fmt.Println(nums, nums1)

	nums1 = append(nums1, 6)
	fmt.Println(nums, nums1)

	nums = append(nums, 1)
	fmt.Println(nums, nums1)

	// Output:
	//[]int{0, 0, 0} 3 5
	//[0 0 0] [0 0]
	//[0 8 0] [8 0]
	//[0 8 0] [8 0 6]
	//[0 8 0 1] [8 0 1]
}

队列

先进先出(在队列尾添加,在队列头部移除)

package main

import "fmt"

func ExampleQueue() {
	queues := []int{}
	// 入队列
	queues = append(queues, 1)
	queues = append(queues, 2)
	queues = append(queues, 3)
	fmt.Println(queues)

	// 出队列
	queues = queues[1:]
	fmt.Println(queues)

	// Output:
	//[1 2 3]
	//[2 3]
}

堆栈

先进后出(在队列头添加,在队列头部移除)

package main

import "fmt"

func ExampleStack() {
	stacks := []int{}
	// 入堆栈
	stacks = append(stacks, 1)
	stacks = append(stacks, 2)
	stacks = append(stacks, 3)
	fmt.Println(stacks)

	// 出堆栈
	stacks = stacks[:len(stacks)-1]
	fmt.Println(stacks)

	// Output:
	//[1 2 3]
	//[1 2]
}

多维切片

package main

import "fmt"

func ExampleManyStack() {
	s1 := [][]int{}
	s2 := make([][]int, 3)
	fmt.Printf("%T\n", s2)

	s1 = append(s1, []int{1, 2, 3})
	s1 = append(s1, []int{6, 7, 8, 9})
	fmt.Println(s1)
	fmt.Println(s1[1][3])

	// Output:
	//[][]int
	//[[1 2 3] [6 7 8 9]]
	//9
}

数组 VS 切片

  • 数组是值类型,切片是指针类型

Golang 中所有赋值都是值传递

package main

import "fmt"

func ExampleArrayVsStack() {
	// 切片赋值修改的是指针指向同一块内存空间,修改时同时发生改变
	s1 := []int{1, 2, 3}
	s2 := s1
	s2[0] = 6
	fmt.Println(s1, s2)

	// 数组赋值时,会新开辟一段地址空间,修改值互不影响
	a1 := [3]int{1, 2, 3}
	a2 := a1
	a2[0] = 6
	fmt.Println(a1, a2)

	// Output:
	//[6 2 3] [6 2 3]
	//[1 2 3] [6 2 3]
}

排序

  • sort 模块支持对切片和用户定义的集合进行排序。
package main

import (
	"fmt"
	"sort"
)

func ExampleSliceSort() {
	s1 := []int{3, 1, 2}
	sort.Ints(s1)
	fmt.Println(s1)

	str := []string{"ab", "sd", "321"}
	sort.Strings(str)
	fmt.Println(str)
	// Output:
	//[1 2 3]
	//[321 ab sd]
}
最新评论
加载中...
Home Archives Categories Tags Statistics