ZKX's LAB

泛型和元编程的模型:Java, Go, Rust, Swift, D等

2020-11-12新闻19

在程序设计的时候,我们通常希望使用同样的数据结构或算法,就可以处理许多不同类型的元素,比如通用的List或只需要实现compare函数的排序算法。对于这个问题,不同的编程语言已经提出了各种各样的解决方案:从只是提供对特定目标有用的通用函数(如C,Go),到功能强大的图灵完备的通用系统(如Rust,C++)。在本文中,我将带你领略不同语言中的泛型系统以及它们是如何实现的。我将从C这样的不具备泛型系统的语言如何解决这个问题开始,然后分别展示其他语言如何在不同的方向上逐渐添加扩展,从而发展出各具特色的泛型系统。

泛型是元编程领域内通用问题的简单案例:编写可以生成其他程序的程序。我将描述三种不同的完全通用的元编程方法,看看它们是如何在泛型系统空的不同方向进行扩展:像Python这样的动态语言,像Template Haskell这样的过程宏系统,以及像Zig和Terra这样的阶段性编译。

概述

下图包含了本文讨论的所有语言的泛型系统,用以概述本文主要内容以及它们是如何结合在一起的。

基本想法

假设我们用一种没有泛型系统的语言进行编程,我们想实现一个通用的堆栈数据结构,它对任何数据类型都有效。困难在于我们写的每一个函数和类型定义都只对那些大小相同、复制方式相同、行为相同的数据有效。

如何解决这个问题?有两个基本的想法,一是想办法让所有数据类型在我们的数据结构中有同样的行为方式,二是对我们的数据结构进行多份拷贝,并稍作调整,以特定的方式处理每种数据类型。这两个想法构成了两大类解决泛型问题的基础方法,即"装箱 "和 "单态化"。

装箱是指我们把所有的东西都放在统一的 "盒子 "里,使它们的行为方式都一样。通常是通过在堆上分配内存,只在数据结构中放指针来实现的。我们可以让不同类型的指针有同样的行为方式,这样,同样的代码就可以处理所有的数据类型了。然而这种做法可能要付出额外的内存分配、动态查找和缓存丢失的代价。在C语言中,这相当于让你的数据结构存储void*指针,也需要将你的数据指针转换为void*或从void*进行类型转换(如果数据还没有在堆上,则在堆上分配)。

#技术编程

随机阅读

qrcode
访问手机版