Golang Go语言中 slice 切片的一个疑问
代码里面看到一个 reset 函数,函数里面有个下面的语句,t.a 是个 slice 类型
t.a = t.a[:0]
这个写法跟 t.a = nil
有啥区别吗?
Golang Go语言中 slice 切片的一个疑问
t.a[:0] 后面 append 的时候会复用底层已经申请的内存
更多关于Golang Go语言中 slice 切片的一个疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
a[:0]是一个长度为 0 的切片吧
t.a = t.a[:0]
底层的数组没有释放, 只是 把 切片的当前 len 设置成了 0t.a = nil
直接把当前的切片设置成空了,底层的数据和当前切片分开了, runtime 可以把 底层的数组回收了
t.a[:0]只是把长度清零,nil 是把整个对象清零了
t.a = t.a[:0]
相当于把 slice 结构里的 len 改为 0 了,cap 保持不变。跟 #1 说得一样,append 的时候,在数量<=cap 时,就不会触发 grow 了。
t.a = nil
原来底层数组可能就要被回收了。
go 中很多基本的值类型都不是纯粹的值(凡是存储了指针成员的值类型都是如此)。
这导致在 Go 中很多时候需要思考指针,会造成一定的心智负担,复制一个带有指针的值类型对象会导致新值和原来的值底层能够同时访问访问指针指向的对象。
slice 的切片操作本质上是共享了底层的指针成员,然后修改了长度字段,我个人是不喜欢这种设计的(算是为了性能做的妥协).
如果值类型是不可变类型(即它的全部字段成员在初始化后就不再可变),那这种心智负担就会降低(string 类型就是如此)。
😅实在不敢同意楼上这大哥在胡言乱语什么鸟东西
😅实在不敢同意楼上这大哥在胡言乱语什么鸟东西
为了防止被人说我乱喷。。我回一下吧。
你所说的所有东西都和指针没有关系。
首先楼主的问题就和指针八竿子打不着,更别说指针封装在 silce 里面根本不让你外部调用。楼主的问题只有一个原因,go 没有给一个 clean()函数的语法糖,让没有太多经验的人对这行代码摸不着头脑,而这帮 C 语言过来的人却习惯了这样的不直观表达方式作为解决方案。
你说的 slice copy 浅拷贝的问题。这没有指针的 java 也有这问题。这和指针也没有关系。所以你还需要一个 b := slice.clone() 的语法糖。
但是你不想要这个,你想要的是比 rust 交出所有权更先进的=即是 deep copy 。在各大语言还在努力用引用解决性能问题的时候,我们做到了人人平等,每个变量都拥有平等公开的享用硬件的权力。
如果值类型是不可变类型,心智负担会下降,我一直时间无法想象如何写插入和排序功能。突然又想起我刚入行遇到的老师傅对我说的话,管他呢,先 new 10M 内存。
这种技巧不应该封装成函数
go 做的那么精简, 不是为了方便添油加醋
如果连 go 的基本数据结构都不愿意看, 就不要写 go, 也不要问
Marshal 一下你就能看出区别了 一个是[]一个是 null
说明 0 长度切片跟空对象的区别
我觉得 #6 说的没太大毛病,就是说的太绕,不熟悉的人难以理解。Go 的 slice 设计本来就是个大坑,是缺乏思考或者说设计上懒惰的直接体现。append 操作返回值的模糊性导致相当场合 append 只有 x=append(x, blah) 这一个用法。
懒得和看不懂的人解释,go 选择在栈上常用的值类型中存储指针这种设计,并将其用在了内置的几大核心类型中,这个设计对于任何不是从 C 语言学过来的人理解其行为都是晦涩的,虽然是为了降低 GC 的负担,但我不认为这个设计是值得,这个设计导致 go 中很多基础的 API 看上去就非常丑陋,你说的 x=append(x, blah) 只是一个典型案例。go 的 goroutine 和接口组合都是很好的设计,降低了心智负担。但 slice 的底层模式导致的指针的无孔不入,对于我这个写惯了 js/java/c#/python 的人来说,是非常不喜欢的,明显破坏了编程语言的简洁和清晰度。
在Go语言中,slice(切片)是一个非常重要的数据结构,它提供了对底层数组的抽象和灵活的操作。针对你的疑问,这里有几个常见的slice概念和操作点,希望能解答你的疑惑:
-
slice的本质:slice是一个包含三个字段的数据结构:指向数组的指针(Pointer)、切片的长度(Length)以及切片的容量(Capacity)。这意味着slice是对数组的一个窗口或视图,而不是数组的拷贝(除非显式进行拷贝操作)。
-
slice的切片:可以通过对已有的slice进行切片操作来创建一个新的slice,新slice将共享原始slice的底层数组。例如,
s2 := s[1:4]
会创建一个新的slice,它包含s中从索引1到索引3(不包括4)的元素。 -
append操作:向slice添加元素时,如果slice的容量不足,Go会自动分配一个新的底层数组,并将现有元素复制到新数组中,然后添加新元素。这意呀着append操作可能会改变slice的底层数组。
-
nil slice:一个未初始化的slice,其值为nil,长度为0,容量为0,且没有指向任何数组。
-
内存管理:由于slice是对底层数组的引用,因此在处理slice时需要特别注意内存泄漏和无效引用的问题。确保不再使用的slice能够被垃圾回收。
希望这些解释能帮助你更好地理解Go语言中的slice。如果有更具体的问题或疑惑,欢迎继续提问!