draveness / blog-comments

面向信仰编程
https://draveness.me
140 stars 6 forks source link

为什么 Go 语言没有泛型 · Why's THE Design? · /whys-the-design-go-generics #175

Closed draveness closed 2 years ago

draveness commented 4 years ago

https://draveness.me/whys-the-design-go-generics

yuanjize commented 4 years ago

我平时开发的时候好像除了调用标准库的min/max函数之外好像没啥泛型需求呢。。。

draveness commented 4 years ago

我平时开发的时候好像除了调用标准库的min/max函数之外好像没啥泛型需求呢。。。

你这个够快的...现在也用 Go 吗?

yuanjize commented 4 years ago

@draveness

我平时开发的时候好像除了调用标准库的min/max函数之外好像没啥泛型需求呢。。。

你这个够快的...现在也用 Go 吗?

是呀,用go。最近没事做,所以没事就刷刷。。。

pydr commented 4 years ago

没那么紧急。

lzylyd commented 4 years ago

泛型也算语法糖的一种吧 之前想在go里使用FP思想的map reduce 发现必须得用泛型才行,现在看了下博主的讨论, 感觉泛型需要考虑下才行

draveness commented 4 years ago

泛型也算语法糖的一种吧

是的,不过语法糖这个词范围了,编译器干的活都可以称为语法糖

之前想在go里使用FP思想的map reduce 发现必须得用泛型才行,现在看了下博主的讨论, 感觉泛型需要考虑下才行

map reduce 这些 FP 的函数,可以使用 interface{} + 类型转换来实现,类型转换就是这里的额外开销。

slixurd commented 4 years ago

Java部分讲的不严谨.贴的代码和泛型没有关系,那是interface抽象的好.

"与 C 语言和 C++ 在运行前就已经实现或者生成代码相比,Java 类型的装箱和拆箱会降低程序的执行效率"

boxing只和primitive types/ wrappers转化有关, 泛型运行时效率低是另外一回事.

draveness commented 4 years ago

Java部分讲的不严谨.贴的代码和泛型没有关系,那是interface抽象的好.

那你觉得什么样的例子合适?

"与 C 语言和 C++ 在运行前就已经实现或者生成代码相比,Java 类型的装箱和拆箱会降低程序的执行效率"

boxing只和primitive types/ wrappers转化有关, 泛型运行时效率低是另外一回事.

我发现这引用贴错了

(The Java approach.) Box everything implicitly. This slows execution.

Compared to the implementations the C programmer would have written or the C++ compiler would have generated, the Java code is smaller but less efficient in both time and space, because of all the implicit boxing and unboxing. A vector of bytes uses significantly more than one byte per byte. Trying to hide the boxing and unboxing may also complicate the type system. On the other hand, it probably makes better use of the instruction cache, and a vector of bytes can be written separately.

Russ Cox "The Generic Dilemma" https://research.swtch.com/generic

那你觉得泛型运行时效率低是为啥?因为需要动态派发么,最好是有 Reference,我可以在文中注明存在不同意见。

draveness commented 4 years ago

Java部分讲的不严谨.贴的代码和泛型没有关系,那是interface抽象的好.

我大概明白的你的意思了,例子应该是下面这样的是吧:

func sort(a []T) ... {
}

我觉得这里的示例还好,你有别的更合适的建议么?

slixurd commented 4 years ago

例子的话随便找一个用到泛型的就行了,min/max之类的,主要是你的例子没用到泛型.只用到了接口 static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)

泛型运行时其实效率也不低, 可以跑个benchmark看看. 你贴的引用,那个是在说byte,Byte,byte[]之间的开销吧,这个是boxing的开销,泛型不支持原始类型(T[]不算)这个是个缺点.

draveness commented 4 years ago

泛型运行时其实效率也不低, 可以跑个benchmark看看.

从理论上来说,运行时执行的再快,也没有编译期间就已经把代码生成的快,运行时能做的优化,编译期间展开之后也可以做。

slixurd commented 4 years ago

我看了一下javap的字节码,以及简单做了一下压测,确实有点性能损耗 主要是多了一组LocalVariableTypeTable保留一定程度的泛型信息 另外取数据时,由于泛型擦除的实现(实际存储Object),所以get的时候会显式调用一次checkcast

weitieda commented 4 years ago

在 gg talk 里听到你是大庆的,我也是大庆的,老乡加油。虽然不太懂GO,但如果出了准备买一本支持一下 :)

CodingByteFly commented 4 years ago

如果go2增加了范型,在实际编程中不使用范型语法糖会不会导致golang性能下降?

draveness commented 4 years ago

如果go2增加了范型,在实际编程中不使用范型语法糖会不会导致golang性能下降?

这要看具体实现,个人理解不会造成太大的性能下降,Go 团队肯定会谨慎增加泛型。

zackzhangkai commented 4 years ago
func Stringify(type T stringer)(s []T) (ret []string) {
 for _, v := range s {
  ret = append(ret, v.String()) // now valid
 }
 return ret
}

这段代码中函数名后面有三个括号,第一个括号是参数,最后一个是返回值类型。那么第二个括号中的是啥?

draveness commented 4 years ago
func Stringify(type T stringer)(s []T) (ret []string) {
 for _, v := range s {
  ret = append(ret, v.String()) // now valid
 }
 return ret
}

这段代码中函数名后面有三个括号,第一个括号是参数,最后一个是返回值类型。那么第二个括号中的是啥?

第一个是泛型的类型,第二个是参数,第三个是返回值类型,这个看看就好,最终的方案不一定是这样

zinwalin commented 3 years ago

Go 语言设计与实现, 有pdf文档吗? 多谢

GodL commented 3 years ago

是否可以对比下swift的泛型

draveness commented 3 years ago

Go 语言设计与实现, 有pdf文档吗? 多谢

没有文档

是否可以对比下swift的泛型

应该不会做,好久不写了

CodingByteFly commented 3 years ago

那如果go语言和c++一样使用编译期间类型特化实现泛型,那么在实际编程过程中若是我们用不到go语言的泛型特性,会不会导致最终的二进制文件膨胀和编译缓慢?

PeterlitsZo commented 3 years ago

好像现在支持了?

draveness commented 3 years ago

@PeterlitsZo 好像现在支持了?

确实支持了