• 请不要在回答技术问题时复制粘贴 AI 生成的内容
gitlight
V2EX  ›  程序员

新手最近在学习 Go,学习的时候有个小问题这几天我一直觉得很困扰。。求助一下大佬们

  •  
  •   gitlight · Jan 10, 2023 · 5095 views
    This topic created in 1394 days ago, the information mentioned may be changed or developed.

    Q:当编写实体的 CRUD 接口的时候,到底是向上层传指针呢,还是传实体? 举个例子:

    // 实体
    type person struct {
    	ID   uint
    	name string
    	age  uint
    }
    
    // 指针传递
    func getPerson(ID uint) (*person, error) {
    	return nil,errors.New("err")
    }
    
    // 值传递
    func getPerson_second(ID uint) (person, error) {
    	return person{}, errors.New("err")
    }
    
    

    纠结这个问题其实是因为在写接口的过程中发现,Go 里是没办法让一个实体类直接返回 nil ,只能返回默认构造参数的结构体,不然 ide 会报错,而使用结构体的指针可以返回 nil 。我虽然明白可以通过 err 返回值来处理错误,但是总觉得生成一个和非空的类外表一样的类返回给上层,会有潜在的危险,并且当类比较复杂的时候,可能会产生额外的开销。

    接下来这个延申问题同样很困扰我:像 Go 这样存在指针而且语法很像 C/C++系但同时又存在 GC 的语言,大量使用指针传递对 GC 来说是好还是坏?要是在 IO 密集的 Web 应用场景下,这样大量地使用指针在堆上分配空间会不会加重 GC 的负担,反而会比值传递这种栈复制来得更慢,而不是让程序变得更快?

    Supplement 1  ·  Jan 10, 2023
    谢谢各位的建议,我觉得还是用指针好一些。昨天晚上写出这个问题的时候,我心里已经差不多有答案了,早上去查了一下这个问题的英文版,发现 Stackoverflow 很早就有人问这个问题了,benchmark 的结论是,当结构体不大的时候,传指针和传值开销区别可以忽略。
    在同学推荐给我的时候说 Go 的性能很高,所以下意识地往零成本抽象的去想了,这样看来反而加重了一些思考包袱。。要是搁以前写 spring 早就一把梭写完了
    23 replies  •  2023-01-10 13:40:34 +08:00
    wheeler
    wheeler
    Jan 10, 2023 via iPhone
    1
    go 里面惯例是有 error 的话,就不应该假定返回值是可用的吧。

    大量用指针确实会有你说的问题,但是这种情况还是需要 profile 的。

    个人以为,通常从语意以及上下文选择更为合适。
    CEBBCAT
    CEBBCAT
    Jan 10, 2023 via iPhone
    2
    (O) 并且当类比较复杂的时候,可能会产生额外的开销。

    嘻嘻,Go 的好处就是便于 benchmark 和调试。你可以看看性能上到底有没有差异,又是差了几纳秒。

    关于在有 error 情况下该返回 nil 还是零值的问题,我推荐你看看 Go 自己是怎么处理的,也可以参考一些开源代码。

    我个人是返回零值,因为编译器优化、降低 GC 压力。另外你担心零值被使用是吧?那你再多想一步,如果返回指针,那每次用之前是不是还要判断是不是 nil ?何况有了 error ,解决 error 是当务之急。


    你后面的问题好专业,真厉害,我建议你先 Google 一下。应该会有很多 Golang 性能优化的建议,比如 map value 用 plain 值,hot path 之类的。最好中英一起搜。
    jorneyr
    jorneyr
    Jan 10, 2023
    3
    向上层传指针呢,还是传实体?

    个人觉得相差不大,本来 Go 的运行速度也不快,加上 Go 的内存逃逸分析会自动处理一部分,所以无脑的传指针好了。
    bruce0
    bruce0
    Jan 10, 2023
    4
    1. 一般 error 不是 nii 了 就可以认为这个值是有问题了

    2. 返回指针会导致结构体逃逸, 然后分配到堆上, 如果量大的话 会有 gc 压力

    我一般情况下,如果结构体都是基本类型, 而且字段不多的情况下, 不返回指针, 直接用值拷贝, 没有 gc, 如果结构体的字段多, 会用指针了
    seers
    seers
    Jan 10, 2023 via Android
    5
    取决于 struct 的大小,太大传值会有拷贝开销,太小的传指针会有堆开销
    securityCoding
    securityCoding
    Jan 10, 2023
    6
    鹅厂内部框架返回的是指针类似,比较灵活
    hwdef
    hwdef
    Jan 10, 2023
    7
    大量传指针确实有你说的问题,,可能有潜在危险,gc 负担大。。但传值会增大内存使用量,看怎么取舍了
    luojiedev
    luojiedev
    Jan 10, 2023
    8
    为了统一性,全部使用指针。其实也是符合了 KISS 原则。
    对于你考虑到的 GC 问题,其实是大部分从 C/C++ 转过来的共同的困扰。但是我记得编译器在这块有一定的优化,建议先全部使用指针吧,确定发现有性能问题的时候,再考虑优化吧。前期用最统一,最简单的代码把功能实现出来。
    x1aoYao
    x1aoYao
    Jan 10, 2023
    9
    既没有 Option<T> Result<T, E> 又没有 Exception 就是这样...
    我司一般用的返回指针,比如从数据库里查询实体,GC 消耗有就有吧
    对于判断了 error 是否还要判断 nil 的问题,有些默认的非空,有些用是否空表示数据是否存在(把无数据 error 返回 nil, nil 了, 避免 if err != nil { return err} 直接返回了,不然还要判断 err 的类型或值..
    xylophone21
    xylophone21
    Jan 10, 2023
    10
    外面传一个指针进来,在函数里面赋值. 内存逃逸问题,空对象问题,都解决了. C/C++里都是这么干的, 用起来会烦一些, 性能提升可能也不多, 看你的场景到底在不在乎, 以及这个代码你打算用多久.
    ShayneWang
    ShayneWang
    Jan 10, 2023
    11
    遇事不决用指针
    maigebaoer
    maigebaoer
    Jan 10, 2023 via Android
    12
    @ShayneWang 确实如此,Go 很狗😃
    fioncat
    fioncat
    Jan 10, 2023
    13
    可以期待一下 go1.20 的 arena ,你可以自己决定对象什么时候释放。

    https://github.com/golang/go/issues/51317
    dobelee
    dobelee
    Jan 10, 2023
    14
    日常业务开发直接指针。统一规范。如果大的用指针小的用结构体太鸡肋了,维护迭代也是要额外成本的。
    maigebaoer
    maigebaoer
    Jan 10, 2023 via Android
    15
    @xylophone21 标准库的 read
    bli22ard
    bli22ard
    Jan 10, 2023
    16
    除非你确实需要给调用者返回一个副本,否则就应该使用指针
    allgy
    allgy
    Jan 10, 2023
    17
    别纠结,这个问题不应该是你继续往前走的绊脚石
    aiqinxuancai
    aiqinxuancai
    Jan 10, 2023
    18
    每当接触新语言的时候,总是会遇到,实现这个功能最好的写法最正确的写法是什么的疑问。
    我的总结下来就是,暂时不要过于纠结这些,真的没有必要,一些东西是循环渐进的,这些没必要的担忧只会影响你学习的进度,先实现功能,等过一年,再来看看你的老代码,你应该就知道该怎么做了。
    当年学 C\C++,就是最简单的查找文本,文本对比等等基础方法都一堆,你总不能写的时候先去把每一种都实现实现,再对比对比速度吧,循环几十万次,差个那几 ms ,没必要的。
    summerLast
    summerLast
    Jan 10, 2023
    19
    在 rust 中就不会有这个问题
    777777
    777777
    Jan 10, 2023
    20
    传值,我就不喜欢用指针,因为如果 error 忘了出来,整个程序 nil 空指针会 panic
    hxysnail
    hxysnail
    Jan 10, 2023
    21
    我的项目都是统传递指针,保持简单;另一方面,指针也更加灵活。至于 GC 性能问题,等出现再说,肯定有解决手段,总不能因为性能退回去写汇编吧。项目迭代有一条原则,就是不要过早做性能优化,心里有数就行。
    Trepverter
    Trepverter
    Jan 10, 2023
    22
    OP 能否分享一下 StackOverflow 的英文帖子链接
    looplj
    looplj
    Jan 10, 2023
    23
    写业务,传值,CPU 都不是业务代码的性能瓶颈。
    写业务,最好是减少副作用,防止在上面地方修改了值都不知道,很难排查。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   4728 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 68ms · UTC 09:12 · PVG 17:12 · LAX 01:12 · JFK 04:12
    ♥ Do have faith in what you're doing.