Go基础系列:Go slice分片切片详解

slice表示切片(分片),例如对一个数组进行切片,取出数组中的一部分值。在现代编程语言中,slice(切片)几乎成为一种必备特性,它可以从一个数组(列表)中取出任意长度的子数组(列表),为操作数据结构带来非常大的便利性,如python、perl等都支持对数组的slice操作,甚至perl还支持对hash数据结构的slice。

但Go中的slice和这些语言的slice不太一样,前面所说的语言中,slice是一种切片的操作,切片后返回一个新的数据对象。而Go中的slice不仅仅是一种切片动作,还是一种数据结构(就像数组一样)。

slice的存储结构

Go中的slice依赖于数组,它的底层就是数组,所以数组具有的优点,slice都有。且slice支持可以通过append向slice中追加元素,长度不够时会动态扩展,通过再次slice切片,可以得到得到更小的slice结构,可以迭代、遍历等。

实际上slice是这样的结构:先创建一个有特定长度和数据类型的底层数组,然后从这个底层数组中选取一部分元素,返回这些元素组成的集合(或容器),并将slice指向集合中的第一个元素。换句话说,slice自身维护了一个指针属性,指向它底层数组中的某些元素的集合

例如,初始化一个slice数据结构:

slice := make([]int, 3,5) // 输出slice fmt.Println(my_slice) // 输出:[0 0 0]

这表示先声明一个长度为5、数据类型为int的底层数组,然后从这个底层数组中从前向后取3个元素(即index从0到2)作为slice的结构。

如下图:

 

每一个slice结构都由3部分组成:容量(capacity)、长度(length)和指向底层数组某元素的指针,它们各占8字节(1个机器字长,64位机器上一个机器字长为64bit,共8字节大小,32位架构则是32bit,占用4字节),所以任何一个slice都是24字节(3个机器字长)

  • Pointer:表示该slice结构从底层数组的哪一个元素开始,该指针指向该元素
  • Capacity:即底层数组的长度,表示这个slice目前最多能扩展到这么长
  • Length:表示slice当前的长度,如果追加元素,长度不够时会扩展,最大扩展到Capacity的长度(不完全准确,后面数组自动扩展时解释),所以Length必须不能比Capacity更大,否则会报错

对上面创建的slice来说,它的长度为3,容量为5,指针指向底层数组的index=0。

可以通过len()函数获取slice的长度,通过cap()函数获取slice的Capacity。

1
2
3
4
my_slice := make([]int,3,5)

fmt.Println(len(my_slice))  // 3
fmt.Println(cap(my_slice))  // 5

还可以直接通过print()或println()函数去输出slice,它将得到这个slice结构的属性值,也就是length、capacity和pointer:

1
2
my_slice := make([]int,3,5)
println(my_slice)      // [3/5]0xc42003df10

[3/5]表示length和capacity,0xc42003df10表示指向的底层数组元素的指针。

务必记住slice的本质是[x/y]0xADDR,记住它将在很多地方有助于理解slice的特性。另外,个人建议,虽然slice的本质不是指针,但仍然可以将它看作是一种包含了另外两种属性的不纯粹的指针,也就是说,直接认为它是指针。其实不仅slice如此,map也如此。

创建、初始化、访问slice

有几种创建slice数据结构的方式。

一种是使用make():

1
2
3
4
5
// 创建一个length和capacity都等于5的slice
slice := make([]int,5)

// length=3,capacity=5的slice
slice := make([]int,3,5)

make()比new()函数多一些操作,new()函数只会进行内存分配并做默认的赋0初始化,

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 这个错误通常表示你正在尝试使用不可哈希的切片类型作为字典的键或集合的元素,但是切片类型是不可哈希的,因此会引发该错误。 要解决这个问题,你可以考虑将切片类型转换为元组类型,因为元组类型是可哈希的,例如: ``` my_dict = {(1,2,3): 'value'} # 使用元组类型作为字典的键 my_set = {(1,2,3), (4,5,6)} # 使用元组类型作为集合的元素 my_slice = slice(1, 5) my_tuple = tuple(my_slice) # 将切片类型转换为元组类型 ``` 这样就可以避免 TypeError: unhashable type: 'slice' 这个错误了。 ### 回答2: TypeError: unhashable type: 'slice'是Python中的一个错误类型。这个错误通常在使用slice类型的对象作为字典的键或集合的元素时出现。 slice是Python中的一个内置函数,用于切片操作。它通常用于从序列中选取一部分元素形成新的序列。 但是,slice对象是不可哈希的(unhashable),这意味着它们不能作为字典的键或集合的元素。字典和集合在内部使用哈希表来实现快速的查找和访问,而哈希表要求键或元素必须是可哈希的类型,也就是能够通过hash()函数生成哈希值的类型。 如果我们尝试将slice对象作为字典的键或集合的元素,Python解释器会抛出TypeError: unhashable type: 'slice'错误,提示我们slice对象是不可哈希的。 解决这个问题的方法是,将slice对象转换为可哈希的类型,例如将其转换为元组。这样就可以将它们用作字典的键或集合的元素,在进行操作时不会出现TypeError。例如: ```python my_dict = {} my_slice = slice(1, 5) my_tuple = tuple(my_slice) my_dict[my_tuple] = "Hello" print(my_dict) # 输出:{(1, 5): "Hello"} ``` 总结来说,TypeError: unhashable type: 'slice'错误是由于尝试将不可哈希的slice对象用作字典键或集合元素而引起的。解决这个问题的方法是将slice对象转换为可哈希的类型,例如元组。 ### 回答3: TypeError: unhashable type: 'slice' 是一种常见的错误类型,它通常发生在以切片作为字典或集合的键时。 在Python中,字典和集合的键需要是可哈希(hashable)的。可哈希的对象是指在其生命周期中不可改变的对象,比如字符串、整数和元组。然而,切片对象是不可哈希的,因为它们可以被修改。 例如,以下代码会引发该错误: ``` my_dict = {slice(1, 5): "value"} ``` 由于切片对象是不可哈希的,因此将其作为字典的键是不允许的,会导致抛出 TypeError: unhashable type: 'slice'。 解决该错误的方法有以下几种: 1. 修改代码逻辑,不要使用切片作为字典或集合的键。 2. 将切片对象转换为可哈希的对象,比如将切片对象转换为元组,然后将元组作为键。 例如,可以修改以上示例代码的方式如下: ``` my_dict = {(1, 5): "value"} ``` 这样就可以避免 TypeError: unhashable type: 'slice' 错误的发生。 总结来说,TypeError: unhashable type: 'slice' 错误通常发生在尝试将切片对象作为字典或集合的键时。解决该错误的方法包括修改代码逻辑,或将切片对象转换为可哈希的对象。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值