【GO语言高级编程学习】之语言基础——数组字符串和切片

数组、字符串和切片

数组、字符串和切片是Go语言中常用的三种数据类型,它们在底层原始数据有着相同的内存结构,在上层,因为语法的限制而有着不同的行为表现。

数组

Go语言的数组和其他语言中的数组的操作基本一致,是由由固定长度的特定类型元素组成的序列,正是因为固定长度,导致其很少被使用。
数组的定义如下

	var a [3]int                    // 定义长度为 3 的 int 型数组, 元素全部为 0
	var b = [...]int{1, 2, 3}       // 定义长度为 3 的 int 型数组, 元素为 1, 2, 3
	var c = [...]int{2: 3, 1: 2}    // 定义长度为 3 的 int 型数组, 元素为 0, 2, 3
	var d = [...]int{1, 2, 4: 5, 6} // 定义长度为 6 的 int 型数组, 元素为 1, 2, 0, 0, 5, 6

Go 语言中数组是值语义。一个数组变量即表示整个数组,它并不是隐式的指向第一个元素的指针(比如 C 语言的数组),而是一个完整的值。这句话如何理解,我们知道在C++语言中定义一个数组,这个数组a并不表示整个数组,它是指向该数组第一个元素的指针,在下面的例子中可以通过打印 a a a 来查看其地址。但是在Go语言中 a a a 就表示整个数组,所以可以把数组看成是一种特殊类型的结构体。

#include<iostream>
using namespace std;
int main()
{
	int a[5] = { 1,2,3,4,5 };
	cout << a << endl; // 000000D3AD2FF758
	return 0;
}
	var a = [...]int{1, 2, 3} // 定义长度为 3 的 int 型数组, 元素为 1, 2, 3
	var b = &a
	fmt.Println(a) // [1 2 3]
	fmt.Println(b) // &[1 2 3]

同样的,Go语言中的数组可以用于不同的数据类型,如字符串数组、结构体数组、函数数组、接口数组、管道数组等。数组的遍历也比较简单这里就不再赘述了。

字符串

字符串是一个长度固定只读的字节数组。如果你想通过下标的方式修改对应下表的值时,就会提示报错cannot assign to s[0] (value of type byte)。如果非要修改要将将 string 转为 []byte 修改后,再转为 string ,具体代码如下。

func main() {
	str := "hello world"
	strBytes := []byte(str)
	strBytes[0] = 'H'
	str = string(strBytes)
	fmt.Println(str)
}

字符串结构由两个信息组成:第一个是字符串指向的底层字节数组,第二个是字符串的字节的长度。下面是字符串“Hello, world”本身对应的内存结构。data 代表指向的底层的字节数组,len 为长度。
字符串“Hello, world”内存结构
字符串虽然不是切片,但是支持切片操作,可以通过索引来得到对应的字符串

s := "hello, world"
hello := s[:5]
world := s[7:]

s1 := "hello, world"[:5]
s2 := "hello, world"[7:]

切片

Go语言中的切片和C++STL中的vector非常相似,都是动态数组。结构定义如下

type SliceHeader struct {
    Data uintptr
    Len  int
    Cap  int
}

其中Cap表示最大容量。如果未指定容量,则默认为与长度相同。

// 切片的定义
var (
    a []int               // nil 切片, 和 nil 相等, 一般用来表示一个不存在的切片
    b = []int{}           // 空切片, 和 nil 不相等, 一般用来表示一个空的集合
    c = []int{1, 2, 3}    // 有 3 个元素的切片, len 和 cap 都为 3
    d = c[:2]             // 有 2 个元素的切片, len 为 2, cap 为 3
    e = c[0:2:cap(c)]     // 有 2 个元素的切片, len 为 2, cap 为 3
    f = c[:0]             // 有 0 个元素的切片, len 为 0, cap 为 3
    g = make([]int, 3)    // 有 3 个元素的切片, len 和 cap 都为 3
    h = make([]int, 2, 3) // 有 2 个元素的切片, len 为 2, cap 为 3
    i = make([]int, 0, 3) // 有 0 个元素的切片, len 为 0, cap 为 3
)
// 切片的遍历,和数组类似
    for i := range a {
        fmt.Printf("a[%d]: %d\n", i, a[i])
    }
    for i, v := range b {
        fmt.Printf("b[%d]: %d\n", i, v)
    }
    for i := 0; i < len(c); i++ {
        fmt.Printf("c[%d]: %d\n", i, c[i])
    }

切片的增加、删除操作

	var a []int
	a = append(a, 1)                       // 追加 1 个元素
	a = append(a, 2, 3, 4)                 // 追加多个元素, 手写解包方式
	a = append(a, []int{5, 6, 7, 8, 9}...) // 追加 1 个切片, 切片需要解包
	a = append([]int{0}, a...)             // 在开头添加 1 个元素
	i := 5
	x := 6
	a = append(a[:i], append([]int{x}, a[i:]...)...) // // 在第 i 个位置插入 x

	a = append(a, 0)     // 切片扩展 1 个空间
	copy(a[i+1:], a[i:]) // a[i:] 向后移动 1 个位置
	a[i] = x             // 设置新添加的元素

	y := []int{2, 3, 3}
	a = append(a, y...)       // 为 x 切片扩展足够的空间
	copy(a[i+len(y):], a[i:]) // a[i:] 向后移动 len(x) 个位置
	copy(a[i:], y)            // 复制新添加的切片

	N := 2
	b := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
	b = b[:len(b)-1]            // 删除尾部 1 个元素
	b = b[:len(b)-N]            // 删除尾部 N 个元素
	b = append(b[:0], b[1:]...) // 删除开头 1 个元素
	b = append(b[:0], b[N:]...) // 删除开头 N 个元素

	b = b[:copy(b, b[1:])]        // 删除开头 1 个元素
	b = b[:copy(b, b[N:])]        // 删除开头 N 个元素
	b = append(b[:i], b[i+1:]...) // 删除中间 1 个元素
	b = append(b[:i], b[i+N:]...) // 删除中间 N 个元素

	b = b[:i+copy(b[i:], b[i+1:])] // 删除中间 1 个元素
	b = b[:i+copy(b[i:], b[i+N:])] // 删除中间 N 个元素
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值