“泛型”支持实现:Go vs Java vs CPP

1 简述

Go语言并不支持范型编程(某些内置函数是支持范型的,但是用户自定义函数不支持范型),但是可以借助reflect来一定程度上弥补这部分能力的缺失,因为要靠运行时计算所以有运行时开销,性能比不上真正的范型实现。

Java支持真正的“范型”,泛型编程的好处是,编译时对类型安全性进行检查,并且模板参数可以是任意类型不用做类型转换,既安全又方便。由于是在编译时进行类型检查,并且Java编译器会对类、方法、变量级别的模板参数进行类型擦除(Type Erasure,简单理解就是将模板参数替换成Object类型或者第一个Bound的类型),无运行时开销,比Go借助反射模拟范型性能好,也不用像C++一样拷贝代码引起编译速度下降或者代码尺寸膨胀。点击查看:Java-Type-Erasure

C++通过“模板”来支持“范型”编程,之所以加引号,是因为C++不是真正的支持范型编程,模板特例化时编译器其实是生成了一个新类的代码。C++模板是通过Macro来进行处理的,相当于复制、粘贴了类模板的代码,并替换了模板参数类型。简言之,就是一个高级的Macro处理系统。但是因为拷贝了代码,代码膨胀导致了编译速度下降、文件尺寸增加。

网上有很多相关的讨论,这里举个示例简单总结一下。

2 C++ 类模板

#include <iostream>
using namespace std;

template <typename T>
class Calc{
    T t1;
    T t2;
public:
    T Add(T t1, T t2) {
        return t1 + t2;
    }
};

int main() {
    Calc<int> calc_int;
    auto sum_int = calc_int.Add(1, 2);
    cout << "1 + 2 = " << sum_int << endl;
    
    Calc<float> calc_flt;
    auto sum_flt = calc_flt.Add(1.1, 2.2);
    cout << "1.1 + 2.2 = " << sum_flt << endl;
    
    return 0;
}

这里其实是创建了两个不同的类,objdump -dS可以很清晰地看到至少创建了两个不同的方法Add(T, T),可能会有人认为这是函数重载中的name mangling,其实不是,确实是生成了两个不同的类型,这个可以通过DWARF相关信息看出来,首先g++ -s main.cpp得到汇编后文件main.s,然后查看该文件内容并搜索Calc,下面两个分别表示Calc<float>模板实例以及Calc<int>模板实例,二者确实属于两个不同的类型,一个是用Ltypes95来标识,一个是用Ltypes47来标识。

go反射 vs java泛型 vs cpp模板

3 Java范型

Java中范型的实现依赖于Java中的类继承机制、类型擦除、类型转换来实现,最终只会有一个类的示例。

编译时,编译器会对模板参数T进行类型擦除,这里有两种处理的情形:

  • 模板参数T,没有绑定一个类型(如T extends Comparable),那么类型擦除后,模板参数T会用Object进行替代,同时生成对应的类型转换的代码;
  • 模板参数T,有限制类型(如T extends Comparable限定了模板实参必须实现Comparable接口),那么类型擦除后,模板参数T就用这第一个bound的类型Comparable代替,同时生成对应的类型转换代码。

需要注意的是,编译时类型擦除虽然会对源码做一定的调整,某些信息看似丢失了,比如List<String> lst被擦除后变为了List<Object> lst,在运行时我们依然可以通过反射机制来获取lst的元素类型为String,则是为什么呢?这是因为类型擦除并不是删除所有类型信息,模板实参的信息会以某种形式保存下来,以便反射时使用。

// 类型擦除前代码
List<String> lst = new ArrayList();
lst.Add("hello");
lst.Add("world");
Iterator it = lst.iterator();
for ; it.hasNext(); {
    String el = it.Next();
}

// 类型擦除后代码
List lst = new ArrayList();         // 模板实参String,擦除为Object
lst.Add("hello");                   // hello为String,IS-A Object关系成立
lst.Add("world");                   // ...
Iterator it = lst.iterator();       
for ; it.hasNext(); {
    String el = (String) it.Next(); // 编译器自动插入类型转换的代码
}

由此可见,Java的范型实现,既不会像C++那样多创建类导致代码体积膨胀,也不会带来运行时开销,也没有破坏反射依赖的信息。

4 go泛型

Go1不支持范型,但是它可以结合interface{}以及reflect来模拟范型。反射的性能大约有几百ns级别的性能损耗,和范型实现比,还是存在一定的性能差距。

Go2已经中已经计划支持泛型了,拭目以待。

总结

对“泛型”这个宽泛的术语,对比了c++、java、go的一些支持和实现上的差异。

您的支持,是我继续创作、分享知识的动力。如果您认为本文不错,请点赞、转发、赞赏 :)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容