Go基础笔记_5_数组切片

一. 数组

1. 介绍

数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整形、字符串或者自定义类型。更多的是使用切片

数组是单一类型的元素的编号序列,称为元素类型。
元素的数量称为数组的长度,并且永远不会是负数。
数组在规划内存的详细布局时很有用。

  • 数组是值。将一个数组分配给另一个数组会复制所有元素。
  • 特别是如果将数组传递给函数,它将收到数组的副本,而不是指向它的指针。
  • 数组的大小是其类型的一部分。类型[10]int 和[20]int是不同的。
  • 不同的数组总是代表不同的存储。

2. 数组使用

数组元素可以通过索引(位置)来读取(或修改),索引从0开始,第一个元素索引为 0,第二个索引为 1,以此类推。数组的下标取值范围是从0开始,一直到长度减1。

// 声明和初始化数组
var name [SIZE]type
// 数组赋值
name[index] = value

数组访问

package main

import "fmt"

func main() {
    
    
	// 定义5个整数的数组
	var arr [5]int
	fmt.Println("第一个元素arr[0]=", arr[0], "\n最后一个元素arr[len(arr)-1]=", arr[len(arr)-1])
	// 打印索引和元素
	for i, v := range arr {
    
    
		fmt.Printf("索引:%d 元素:%d\n", i, v)
	}
}

# 打印结果
第一个元素arr[0]= 0 
最后一个元素arr[len(arr)-1]= 0
索引:0 元素:0
索引:1 元素:0
索引:2 元素:0
索引:3 元素:0
索引:4 元素:0

数组比较

// ... 表示数组长度根据初始个数
arr2 := [...]int{
    
    1, 2, 3, 4, 5}
fmt.Printf("%T\n", arr2)
arr3 := [...]int{
    
    1, 2, 3, 4, 6}
// arr2和arr3 元素个数和类型相同才能比较
if arr2 == arr3 {
    
    
    fmt.Println("arr2 == arr3")
} else {
    
    
    fmt.Println("arr2 != arr3")
}

//结果为
[5]int
arr2 != arr3

数组赋值

var arr4 [2]string
// 赋值
arr4[0] = "a"
fmt.Println("第一个元素:", arr4[0])
fmt.Println("第二个元素:", arr4[1])

第一个元素: a
第二个元素:

3. 多维数组

var name [size1]...[sizen]type
// 二维数组
var arr5 [3][2]int
fmt.Println("arr5[0][1]:", arr5[0][1])
//声明初始化第一个元素,索引2的元素,此时的索引为1的默认为0
arr5 = [3][2]int{
    
    0: {
    
    1, 2}, 2: {
    
    6, 7}}
fmt.Println("arr5[0][1]:", arr5[0][1])
fmt.Println("arr5[1][0]:", arr5[1][0])
fmt.Println("arr5[2][1]:", arr5[2][0])
fmt.Println("arr5[2][1]:", arr5[2][1])

// 运行结果
arr5[0][1]: 0
arr5[0][1]: 2
arr5[1][0]: 0
arr5[2][0]: 6
arr5[2][1]: 7

二. 切片

1. 介绍

切片是底层数组的连续段的描述符,并提供对该数组中元素的编号序列的访问。切片包装数组,为数据序列提供更通用、更强大、更方便的接口。
数组的长度不可变,切片可以增加元素。

注意:Go 中的大多数数组编程都是使用切片而不是简单数组完成的。切片本身按值传递
切片包含对底层数组的引用,如果将一个切片分配给另一个切片,则两者都引用同一个数组。
如果函数接受切片参数,则它对切片元素所做的更改将对调用者可见,类似于将指针传递给底层数组。

  • 元素类型相同
  • 切片类型表示其元素类型的所有数组切片的集合。
  • 元素的数量称为切片的长度,并且永远不会是负数。
  • 未初始化切片的值为nil。

2. 切片使用

声明切片
和数组的声明区别是,切片声明无元素个数

// 声明新切片name 切片名称,T 元素类型
var name []T
// 从连续内存区域生成切片
slice [startIndex : endIndex]

从数组中生成切片

package main

import "fmt"

func main() {
    
    
	var arr = [5]int{
    
    1, 2, 3, 4, 5}
	//从数组生成切片
	fmt.Println("切片arr[0:2]:", arr[0:2])
	// 下标为数组最后的下标时候,数组最后一个元素取不出
	fmt.Println("切片arr[0:4]:", arr[0:4])
	// startIndex为0,endIndex缺省时候,取出数组的全部元素
	fmt.Println("arr[0:]:", arr[0:])
	// 切片重置,清空元素
	fmt.Println("arr[0:0]:", arr[0:0])
}

// 结果
切片arr[0:2]: [1 2]
切片arr[0:4]: [1 2 3 4]
arr[0:]: [1 2 3 4 5]
arr[0:0]: []

切片是动态结构,只能与 nil 判定相等,不能互相判定相等。声明新的切片后,可以使用 append() 函数向切片中添加元素。

// 声明字符串类型切片
var strSlice []string
// 声明初始化int类型切片
var intSlice = []int{
    
    1, 2}
fmt.Println("strSlice == nil ", strSlice == nil)
fmt.Println("intSlice == nil ", intSlice == nil)
fmt.Println("len(intSlice) ", len(intSlice))
// append 添加元素
strSlice = append(strSlice, "add_1")
fmt.Println("strSlice ", strSlice)

// 结果
strSlice == nil  true
intSlice == nil  false
len(intSlice)  2
strSlice  [add_1]

3. make构造切片

创建的切片make总是分配一个新的隐藏数组,返回的切片值引用该数组。
make 发生了内存分配操作。

// T元素类型,length该类型分配元素的个数,capacity预分配元素数量
make( []T, length, capacity)
// make构造切片
a := make([]int, 3)
b := make([]int, 3, 6)
fmt.Println("a:", a, "b:", b)
fmt.Println("len(a) ", len(a), "len(b) ", len(b))

// 结果
a: [0 0 0] b: [0 0 0]
len(a)  3 len(b)  3
//产生与分配数组并对其进行切片相同的切片, 如下这两个表达式是等价的
make([]int, 50, 100)
new([100]int)[0:50]

注意:
像数组一样,切片总是一维的,但可以组合起来构造更高维的对象。
对于数组的数组,内部数组在构造上总是相同的长度。
但是对于切片切片(或切片数组),内部长度可能会动态变化。
此外,内部切片必须单独初始化。

4. 二维切片

// 多维切片:name切片名称,[]维度, T类型
var name [][]...[]T
// 二维切片
var c = [][]int{
    
    {
    
    1}, {
    
    2, 3}}
fmt.Println("c[0][0] ", c[0][0])
fmt.Println("c[1][0] ", c[1][0])

//结果
c[0][0]  1
c[1][0]  2

5. 函数

len() 和 cap() 函数

len() 方法获取长度
cap() 方法计算切片最长可以达到多少

len和cap不相等

package main

import "fmt"

func main() {
    
    
	var num = make([]int, 2, 10)
	fmt.Printf("len=%d cap=%d slice=%v\n", len(num), cap(num), num)
}

// 结果
len=2 cap=10 slice=[0 0]

append() 函数

append 向切片动态添加元素,然后返回一个和切片一样类型的切片。
空间不足以容纳足够多的元素时候,切片会按2的倍数扩容。
切片从开头元素插入,会导致已有元素复制一次,性能差不如尾插。

append(slice_name, value)
package main

import "fmt"

func main() {
    
    
	var num = make([]int, 2, 10)
	fmt.Printf("len=%d cap=%d slice=%v\n", len(num), cap(num), num)
	num = append(num, 3, 4, 5, 6, 7, 8, 8, 9, 9, 6)
	fmt.Printf("len=%d cap=%d slice=%v\n", len(num), cap(num), num)
	// 头部追加
	num = append([]int{
    
    100}, num...)
	fmt.Printf("len=%d cap=%d slice=%v\n", len(num), cap(num), num)
}
// 结果
len=2 cap=10 slice=[0 0]
// cap变化,扩容了
len=12 cap=20 slice=[0 0 3 4 5 6 7 8 8 9 9 6]
// 头部增加了元素100
len=13 cap=14 slice=[100 0 0 3 4 5 6 7 8 8 9 9 6]

append组合

append(slice_name,append(slice_name, value))

copy() 函数

copy 函数copy从源slice的src中复制元素到目标dst,并且返回复制的元素的个数

// dst目标切片,能包含src切片,src源切片,dst和src切片类型要相同。返回值:元素个数
copy( dst, src []T) int
package main

import "fmt"

func main() {
    
    
	// copy
	s1 := []int{
    
    1, 2, 3, 4, 5, 6}
	s2 := []int{
    
    9, 8, 7}
	copy(s1, s2)
	// 只会复制s2的前3个元素到s1中,s1的前三个被替换
	fmt.Println("s1:", s1)
	copy(s2, s1)
	// s2的容量容纳不下s1,未复制s1
	fmt.Println("s2:", s2)
}

// 结果
s1: [9 8 7 4 5 6]
s2: [9 8 7]

切片作为参数

Read 函数可以接受切片参数而不是指针和计数;切片内的长度设置读取数据量的上限。

//对缓冲区进行 buf切片
func (f *File) Read(buf []byte) (n int, err error)
    var n int
    var err error
    for i := 0; i < 32; i++ {
    
    
        nbytes, e := f.Read(buf[i:i+1])  // Read one byte.
        n += nbytes
        if nbytes == 0 || e != nil {
    
    
            err = e
            break
        }
    }

猜你喜欢

转载自blog.csdn.net/u010895512/article/details/125951567