编程时,我们经常需要编写“通用”函数,而确切的数据类型并不重要。例如,您可能想编写一个简单的函数来对数字求和。
Go 直到最近才缺乏这个概念,但它是最近添加的(从 1.18 版开始)。所以我把它拿出来转了一圈。
在 Java 中,只要您需要“泛型”容器(数组、映射),并且只要坚持使用函数式惯用语,泛型就可以很好地工作。但是 Java 不会让我按照自己喜欢的方式编写代码。下面是我如何编写一个汇总数字的函数:
整数总和( int [ ] v ) { int夏天= 0 ; for ( int k = 0 ; k < v .长度; k + + ) { 夏天+ = v [ k ] ; } 回归夏天; }
如果我需要支持各种号码类型怎么办?那我想写下面的泛型函数,但是Java不让我写。
// 这个Java代码不会编译 静态< T 扩展数> T sum ( T [ ] v ) { T 夏天= 0 ; for ( int k = 0 ; k < v .长度; k + + ) { 夏天+ = v [ k ] ; } 回归夏天; }
Go 本身不是面向对象的,因此您没有“数字”类。但是,您可以创建自己的通用“接口”来提供相同的功能。所以这里是你如何在 Go 中解决同样的问题:
类型号码接口{ 单位|整数|浮动32 |浮动64 } func sum [ T 数] ( a [ ] T ) T { var 夏天 T 对于_ , v : =范围( a ) { 夏天+ = v } 回归夏天 }
所以,至少在这个例子中,Go 泛型比 Java 泛型更具表现力。性能呢?
如果我将上面的代码应用于整数数组,我会在汇编中得到以下紧密循环:
电脑11: MOVQ ( AX ) ( DX * 8 ) , SI INCQ DX ADDQ SI , CX CMPQ BX , DX JGT pc11
就 Go 而言,这是尽可能高效的。
到目前为止,我给出了一个 A to Go 泛型。
原文: https://lemire.me/blog/2022/07/08/go-generics-are-not-bad/