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

2024-08-14 17:25:41 +08:00
 jlak
前言:
第一次认识 Go 在十几年前了,当时玩着 Python
从那时候印象(没看过代码)里就一直非常好
感觉速度又快又简单
直到最近才开始上手,体验是简单到超乎我的意料
然后感觉深刻的错误判断非常非常的繁琐
几乎每个函数里需要写多个 err!=nil
对于我这种只会写写简单代码的 err!nil 有时超过业务逻辑
但这好处也很大 几乎将所有错误都归到了可视范围

正题:
自从开始正式关注之后,知乎 App 就开始推送大量的 Go 问题的回答(我没有在知乎上关注,应该是根据大数据)
其中绝大部分都是喷 Go 的
而且这个量非常的大 每天都会收到多篇
范围涵盖了 Go 的方方面面
这个量远远超过了我同样关注的 JS/Node
一开始不当回事 但是每天这么多推送
不禁让人重视这个问题
18930 次点击
所在节点    Go 编程语言
125 条回复
yb2313
2024-08-15 21:06:03 +08:00
bang dream it's my go
Trim21
2024-08-15 21:35:19 +08:00
@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
2024-08-15 21:48:19 +08:00
@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
2024-08-15 21:53:25 +08:00
我是 PHP 转 go 的,go 让我觉得很麻烦的一点就是每次修改都不能热更新,需要我重新 run 一次,不像 PHP 改完刷新就行了。 我觉得 go 是世界上最好的语言,但 PHP 是宇宙第一的语言,yyds
hez2010
2024-08-15 22:05:12 +08:00
@james122333 问题就在于错误/异常这种东西恰好不应该通过多返回值来解决,因为错误和正常是互斥的。go 硬是把一个需要用 sum types 表达的东西用 product types 表达了出来。
正确设计应该返回 Result | Error 作为结果,而不是 Result * Error 。
yu1miao
2024-08-15 22:09:10 +08:00
@Trim21 #103 看来确实没那么理想,学到了 :-)
james122333
2024-08-15 22:20:54 +08:00
@hez2010

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

单返回值也只能够一直嵌套结构这种很丑的做法
Trim21
2024-08-15 22:44:48 +08:00
@james122333 #108

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

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

所以 rust 的解决方法是加了一个 ? 操作符,在 Err 时候直接把 Err 返回上层,中止当前函数。
ashong
2024-08-15 22:51:00 +08:00
Go 起码能看懂, 近几天看 tauri 源码,rust 整个就是天书
james122333
2024-08-15 23:31:25 +08:00
@Trim21

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

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

这里说的这个 Result 在 go 里是不存在的,不是结构体那样的东西。结构体和多返回值是一回事。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1064987

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX