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

Go 语言真的有这么破烂不堪吗

  •  1
     
  •   jlak · 36 天前 via iPhone · 12679 次点击
    这是一个创建于 36 天前的主题,其中的信息可能已经有所发展或是发生改变。
    前言:
    第一次认识 Go 在十几年前了,当时玩着 Python
    从那时候印象(没看过代码)里就一直非常好
    感觉速度又快又简单
    直到最近才开始上手,体验是简单到超乎我的意料
    然后感觉深刻的错误判断非常非常的繁琐
    几乎每个函数里需要写多个 err!=nil
    对于我这种只会写写简单代码的 err!nil 有时超过业务逻辑
    但这好处也很大 几乎将所有错误都归到了可视范围

    正题:
    自从开始正式关注之后,知乎 App 就开始推送大量的 Go 问题的回答(我没有在知乎上关注,应该是根据大数据)
    其中绝大部分都是喷 Go 的
    而且这个量非常的大 每天都会收到多篇
    范围涵盖了 Go 的方方面面
    这个量远远超过了我同样关注的 JS/Node
    一开始不当回事 但是每天这么多推送
    不禁让人重视这个问题
    125 条回复    2024-08-18 00:32:57 +08:00
    1  2  
    yb2313
        101
    yb2313  
       35 天前
    bang dream it's my go
    Trim21
        102
    Trim21  
       35 天前
    @yu1miao #100 你把上面那个也改成 var buf io.ByteWriter = &Buffer{} 就看出区别了

    var _ IBuffer = (*Buffer)(nil)
    var _ io.ByteWriter = (*Buffer)(nil)

    func write(w io.ByteWriter) {
    for i := byte(0); i < 10; i++ {
    _ = w.WriteByte(i)
    }
    }

    func writeGeneric[W io.ByteWriter](w W) {
    for i := byte(0); i < 10; i++ {
    _ = w.WriteByte(i)
    }
    }

    func BenchmarkExtract(b *testing.B) {
    var buf io.ByteWriter = &Buffer{}
    for i := 0; i < b.N; i++ {
    write(buf)
    }
    }

    func BenchmarkExtra(b *testing.B) {
    var buf IBuffer = &Buffer{}
    for i := 0; i < b.N; i++ {
    writeGeneric(buf)
    }
    }

    BenchmarkExtract-16 1000000000 4.872 ns/op 0 B/op 0 allocs/op
    BenchmarkExtra-16 1000000000 25.43 ns/op 0 B/op 0 allocs/op
    Trim21
        103
    Trim21  
       35 天前
    @yu1miao #100 准确的说这里有 6 种情况,你 benchmark 跑一下就能看出来泛型实现的问题了。

    这里跟 writeGeneric 直接传结构体的性能跟用接口,并且编译器没有进行 devirtualize 是相同的,并不会像你说的那样专门生成一个 writeGeneric(w *Buffer) error

    如果你传进去的是一个接口,调用开销直接就翻倍了。


    func Benchmark_interface_0(b *testing.B) {
    var buf = &Buffer{}
    for i := 0; i < b.N; i++ {
    write(buf)
    }
    }

    func Benchmark_interface_1(b *testing.B) {
    var buf io.ByteWriter = &Buffer{}
    for i := 0; i < b.N; i++ {
    write(buf)
    }
    }

    func Benchmark_interface_2(b *testing.B) {
    var buf IBuffer = &Buffer{}
    for i := 0; i < b.N; i++ {
    write(buf)
    }
    }

    func Benchmark_generic_0(b *testing.B) {
    var buf = &Buffer{}
    for i := 0; i < b.N; i++ {
    writeGeneric(buf)
    }
    }

    func Benchmark_generic_1(b *testing.B) {
    var buf io.ByteWriter = &Buffer{}
    for i := 0; i < b.N; i++ {
    writeGeneric(buf)
    }
    }

    func Benchmark_generic_2(b *testing.B) {
    var buf IBuffer = &Buffer{}
    for i := 0; i < b.N; i++ {
    writeGeneric(buf)
    }
    }

    Benchmark_interface_0-16 232742709 5.139 ns/op 0 B/op 0 allocs/op
    Benchmark_interface_1-16 434387566 2.794 ns/op 0 B/op 0 allocs/op
    Benchmark_interface_2-16 85636600 14.67 ns/op 0 B/op 0 allocs/op
    Benchmark_generic_0-16 85636600 13.97 ns/op 0 B/op 0 allocs/op
    Benchmark_generic_1-16 54496902 24.23 ns/op 0 B/op 0 allocs/op
    Benchmark_generic_2-16 49954623 24.91 ns/op 0 B/op 0 allocs/op
    maybeok
        104
    maybeok  
       35 天前
    我是 PHP 转 go 的,go 让我觉得很麻烦的一点就是每次修改都不能热更新,需要我重新 run 一次,不像 PHP 改完刷新就行了。 我觉得 go 是世界上最好的语言,但 PHP 是宇宙第一的语言,yyds
    hez2010
        105
    hez2010  
       35 天前
    @james122333 问题就在于错误/异常这种东西恰好不应该通过多返回值来解决,因为错误和正常是互斥的。go 硬是把一个需要用 sum types 表达的东西用 product types 表达了出来。
    正确设计应该返回 Result | Error 作为结果,而不是 Result * Error 。
    yu1miao
        106
    yu1miao  
       35 天前
    @Trim21 #103 看来确实没那么理想,学到了 :-)
    james122333
        107
    james122333  
       35 天前
    @hez2010

    重点在於不是所有错误都是不可接受的 照这种情况便要在接近的外层捕获 而单返回值也不能够表示 return nil, nil 这种状况 所以我才提那个例子 可以处理 error 也可以 panic
    james122333
        108
    james122333  
       35 天前
    @hez2010

    单返回值也只能够一直嵌套结构这种很丑的做法
    Trim21
        109
    Trim21  
       35 天前
    @james122333 #108

    你说的这几个其实都不是问题。

    单返回值也可以表示 return nil, nil , 只要这个 Result 是 *T | Error 就行。你是想的 int | Error 不能 nil ,nil ,但你定义为 *int | Error 肯定可以 nil ,nil 。nil 也是一个 *int 。

    所以 rust 的解决方法是加了一个 ? 操作符,在 Err 时候直接把 Err 返回上层,中止当前函数。
    ashong
        110
    ashong  
       35 天前
    Go 起码能看懂, 近几天看 tauri 源码,rust 整个就是天书
    james122333
        111
    james122333  
       35 天前 via Android
    @Trim21

    这不是白说了吗 我需要同时判断两者
    Trim21
        112
    Trim21  
       35 天前
    @james122333 #111 除非你在 err!=nil 的时候也返回了一个 T ,否则我们说的 Result 是涵盖了你说的这种情况的。
    jiangzm
        113
    jiangzm  
       35 天前
    Go 有一部分奇怪的语法只是为了标新立异,同样是 Google 推出的语言 Dart 就正常很多,类 C 的语法很容易让其他语言开发者上手。
    dwu8555
        114
    dwu8555  
       34 天前
    Hacknews 上最频繁出现的就是 Golang 和 Postgres
    jackblack369
        115
    jackblack369  
       34 天前
    历经过 javaer 、pythoner ,这月开始入坑的 gopher ,感觉挺好,个人挺喜欢
    james122333
        116
    james122333  
       34 天前 via Android
    @Trim21

    你这表示指的是"或"的意思吗 如果是不能表示回传两个 nil 如果是结构含两者那我说过了很丑
    必需得要写新结构
    molika
        117
    molika  
       34 天前
    只能说交叉编译太爽了. 心智负担比 rust 低. 二进制包完爆 py
    写起来习惯就好了.
    xiaocaiji111
        118
    xiaocaiji111  
       34 天前
    做业务没 java 爽,其他还行,当然也得看是什么业务,电商这些,国内只有字节在搞吧,也能搞,但是不太爽。
    mars2023
        119
    mars2023  
       34 天前
    @maybeok #104 你说的热更新问题,在静态语言上都是如此吧;鱼与熊掌不可兼得。
    Trim21
        120
    Trim21  
       34 天前 via Android
    @james122333 这里说的 Result 是提供判断是否为 Error 还是为 result 的能力的,同时判断两者为 nil 就是非 error 并且 *T 为 nil 的情况啊?

    这里说的这个 Result 在 go 里是不存在的,不是结构体那样的东西。结构体和多返回值是一回事。
    james122333
        121
    james122333  
       34 天前 via Android
    @Trim21

    回传*T 非 nil 为成功 回传 error 为失败 回传 nil 为可接受失败(nil,nil)的意思?
    rust 有这能力? 其它语言这样搞还要判断回传类型 又多了麻烦
    cqu1980
        122
    cqu1980  
       34 天前
    @uiosun 不是所有的 err 都需要去处理,所以有些直接_略过就行了
    Trim21
        123
    Trim21  
       33 天前 via Android
    @james122333 有啊
    zizon
        124
    zizon  
       33 天前
    v2 上也很多喷时政的,想明白了就释然了
    lysShub
        125
    lysShub  
       33 天前
    @me1onsoda 用数组啊
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1436 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 63ms · UTC 23:54 · PVG 07:54 · LAX 16:54 · JFK 19:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.