The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
einsdisp

Golang 结构体切片,大家的习惯是切片元素是结构体值还是指针(不考虑性能,仅考虑代码优雅)

  •  
  •   einsdisp · Oct 10, 2020 · 4761 views
    This topic created in 2071 days ago, the information mentioned may be changed or developed.
    type Foobar struct {
    }
    

    切片元素是值

    var s []Foobar
    

    Or:

    切片元素是指针

    var s []*Foobar
    

    不考虑性能,仅考考代码优雅性。

    前一种切片(元素为值)在循环赋值时有不便之处:

    for _, i := range s {
    	i.xxx = yyy
    }
    

    上面的代码实际上是无效的,必须使用索引,于是代码很不优雅:

    for i, _ := range s {
    	s[i].xxx = yyy
    }
    

    但后一种切片(元素为指针),在很多使用场景下同样不方便

    20 replies    2020-10-14 17:47:37 +08:00
    einsdisp
        1
    einsdisp  
    OP
       Oct 10, 2020
    后一种切片(元素为指针),在很多使用场景下同样不方便。

    在使用切片中的某元素时,常常要先解引用(就是说需要写成类似 `*s[i]` 的形式而非 `s[i]`),感觉同样很不优雅
    zarte
        2
    zarte  
       Oct 10, 2020
    ```
    for _, i := range s {
    i.xxx = yyy
    }
    ```
    其他语言这样也不行呀。
    我是用这种。
    JeromeCui
        3
    JeromeCui  
       Oct 10, 2020
    我比较习惯指针,可能是因为我之前写了好几年的 C++吧
    QingXuJiaZhi
        4
    QingXuJiaZhi  
       Oct 10, 2020
    一律优先用指针,遇到特殊情况才直接用结构体。

    另外在 Go 里,给一个结构体添加方法,官方也是提倡优先对其指针添加方法,像这样 func (foobar *Foobar) Method(){}
    richzhu
        5
    richzhu  
       Oct 10, 2020
    我是用上面那种
    labulaka521
        6
    labulaka521  
       Oct 10, 2020 via iPhone
    range 是复制到一个新的对象去了,你再修改也改不到原始的
    simenet
        7
    simenet  
       Oct 10, 2020
    别问,问就是指针
    dodoa
        8
    dodoa  
       Oct 10, 2020
    喜欢用值类型,虽然指针和值类型在传值修改的影响完全不一样,根据使用场景的不同,各自有各自的优势或者说弊端吧。值类型完全不用考虑内存管理的问题
    coderxy
        9
    coderxy  
       Oct 10, 2020
    用指针,性能即优雅。 就像我声明切片的时候尽量指定容量,看着更舒服。
    keepeye
        10
    keepeye  
       Oct 10, 2020
    指针
    damngood
        11
    damngood  
       Oct 10, 2020 via iPhone
    指针性能未必更好. 要考虑 gc 和内存分配这些问题.
    Sasasu
        12
    Sasasu  
       Oct 10, 2020
    在有 gc 的语言中一切常识都要重新考虑。

    一个指针数组填充时需要 N 次内存分配,创建 N + 1 个对象。

    写起来奔放的话 gc 导致的 cpu 使用会比程序真正用到的还要多。

    STW 延迟还好,但是吞吐量就没有了。
    vvmint233
        13
    vvmint233  
       Oct 10, 2020
    所以为啥要加个_, for i := range s {s[i].xxx = yyyy} 也挺好看的啊
    index90
        14
    index90  
       Oct 10, 2020
    同样的问题: https://v2ex.com/t/664610
    snowwalf
        15
    snowwalf  
       Oct 10, 2020
    for i := range s {
    s[i].xxx = yyy
    }
    useben
        16
    useben  
       Oct 10, 2020
    看情况, 小对象直接存值; 大对象一般存指针; 若大对象且频繁创建销毁看情况, 若内存足够直接存值, 若内存紧张存指针, 总之就是 trade-off

    因为切片底层的扩容是根据切片元素分情况的, 值 or 指针. 若是值直接扩容追加到旧内存; 若是指针, 需要判断是否写屏障, 还有 gc 判断啥的, 因此对增加开销.
    lewinlan
        17
    lewinlan  
       Oct 10, 2020 via Android
    无脑指针即可
    mengzhuo
        18
    mengzhuo  
       Oct 10, 2020
    99%指针
    1%为了性能才用 struct
    gamexg
        19
    gamexg  
       Oct 10, 2020
    尽量指针,
    极个别为了性能考虑保存为值,但是使用时也尽量使用指针:

    ```
    list1 := make([]Struct1, 1)

    for i, _ := range list1 {
    v := &list1[i]

    v.A = "11"
    }
    ```
    bluetroy
        20
    bluetroy  
       Oct 14, 2020
    是否考虑过为什么 range 获取到的元素是元素的一个复制?为什么 go 语言要如此设计?人家特地复制出来给你用就怕你瞎改。老老实实写 s[i].xxx = yyy 吧。
    另外:slice[1] = a;slice[1]被放入的是 a 的一个复制,但是使用 slice[1]获取值时获取的是底层值,因此可以直接进行 slice[1].xx =b 。 而 map[1]=a,而获取的时候总是返回 map[1]底层值的一个复制,因此无法 map[1].xx=b 。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2843 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 79ms · UTC 13:46 · PVG 21:46 · LAX 06:46 · JFK 09:46
    ♥ Do have faith in what you're doing.