V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
yujianwjj
V2EX  ›  Go 编程语言

go slice 切片的一个疑问

  •  
  •   yujianwjj · 316 天前 · 1488 次点击
    这是一个创建于 316 天前的主题,其中的信息可能已经有所发展或是发生改变。

    代码里面看到一个 reset 函数,函数里面有个下面的语句,t.a 是个 slice 类型

    t.a = t.a[:0]
    

    这个写法跟 t.a = nil 有啥区别吗?

    13 条回复    2024-01-15 17:42:15 +08:00
    DefoliationM
        1
    DefoliationM  
       316 天前
    t.a[:0] 后面 append 的时候会复用底层已经申请的内存
    Frankcox
        2
    Frankcox  
       316 天前
    a[:0]是一个长度为 0 的切片吧
    bruce0
        3
    bruce0  
       316 天前
    `t.a = t.a[:0]` 底层的数组没有释放, 只是 把 切片的当前 len 设置成了 0

    `t.a = nil` 直接把当前的切片设置成空了,底层的数据和当前切片分开了, runtime 可以把 底层的数组回收了
    muntoya
        4
    muntoya  
       316 天前
    t.a[:0]只是把长度清零,nil 是把整个对象清零了
    Jony4Fun
        5
    Jony4Fun  
       316 天前
    t.a = t.a[:0]
    相当于把 slice 结构里的 len 改为 0 了,cap 保持不变。跟 #1 说得一样,append 的时候,在数量<=cap 时,就不会触发 grow 了。

    t.a = nil
    原来底层数组可能就要被回收了。
    thinkershare
        6
    thinkershare  
       316 天前
    go 中很多基本的值类型都不是纯粹的值(凡是存储了指针成员的值类型都是如此)。
    这导致在 Go 中很多时候需要思考指针,会造成一定的心智负担,复制一个带有指针的值类型对象会导致新值和原来的值底层能够同时访问访问指针指向的对象。
    slice 的切片操作本质上是共享了底层的指针成员,然后修改了长度字段,我个人是不喜欢这种设计的(算是为了性能做的妥协).
    如果值类型是不可变类型(即它的全部字段成员在初始化后就不再可变),那这种心智负担就会降低(string 类型就是如此)。
    mainjzb
        7
    mainjzb  
       316 天前   ❤️ 2
    😅实在不敢同意楼上这大哥在胡言乱语什么鸟东西
    RoccoShi
        8
    RoccoShi  
       316 天前
    😅实在不敢同意楼上这大哥在胡言乱语什么鸟东西
    mainjzb
        9
    mainjzb  
       316 天前
    为了防止被人说我乱喷。。我回一下吧。
    你所说的所有东西都和指针没有关系。
    首先楼主的问题就和指针八竿子打不着,更别说指针封装在 silce 里面根本不让你外部调用。楼主的问题只有一个原因,go 没有给一个 clean()函数的语法糖,让没有太多经验的人对这行代码摸不着头脑,而这帮 C 语言过来的人却习惯了这样的不直观表达方式作为解决方案。
    你说的 slice copy 浅拷贝的问题。这没有指针的 java 也有这问题。这和指针也没有关系。所以你还需要一个 b := slice.clone() 的语法糖。
    但是你不想要这个,你想要的是比 rust 交出所有权更先进的=即是 deep copy 。在各大语言还在努力用引用解决性能问题的时候,我们做到了人人平等,每个变量都拥有平等公开的享用硬件的权力。
    如果值类型是不可变类型,心智负担会下降,我一直时间无法想象如何写插入和排序功能。突然又想起我刚入行遇到的老师傅对我说的话,管他呢,先 new 10M 内存。
    1423
        10
    1423  
       316 天前
    这种技巧不应该封装成函数
    go 做的那么精简, 不是为了方便添油加醋
    如果连 go 的基本数据结构都不愿意看, 就不要写 go, 也不要问
    rekulas
        11
    rekulas  
       316 天前
    Marshal 一下你就能看出区别了 一个是[]一个是 null
    说明 0 长度切片跟空对象的区别
    iseki
        12
    iseki  
       316 天前 via Android
    我觉得 #6 说的没太大毛病,就是说的太绕,不熟悉的人难以理解。Go 的 slice 设计本来就是个大坑,是缺乏思考或者说设计上懒惰的直接体现。append 操作返回值的模糊性导致相当场合 append 只有 x=append(x, blah) 这一个用法。
    thinkershare
        13
    thinkershare  
       313 天前
    @iseki 懒得和看不懂的人解释,go 选择在栈上常用的值类型中存储指针这种设计,并将其用在了内置的几大核心类型中,这个设计对于任何不是从 C 语言学过来的人理解其行为都是晦涩的,虽然是为了降低 GC 的负担,但我不认为这个设计是值得,这个设计导致 go 中很多基础的 API 看上去就非常丑陋,你说的 x=append(x, blah) 只是一个典型案例。go 的 goroutine 和接口组合都是很好的设计,降低了心智负担。但 slice 的底层模式导致的指针的无孔不入,对于我这个写惯了 js/java/c#/python 的人来说,是非常不喜欢的,明显破坏了编程语言的简洁和清晰度。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2853 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 35ms · UTC 08:49 · PVG 16:49 · LAX 00:49 · JFK 03:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.