90

Dave Herman 最近在 Rust 的演讲中说他们从 C++ 中借用了这个属性。我找不到有关该主题的任何内容。有人可以解释一下单态化是什么意思吗?

4

4 回答 4

153

单态化意味着生成通用函数的特殊版本。如果我编写一个提取任何对的第一个元素的函数:

fn first<A, B>(pair: (A, B)) -> A {
    let (a, b) = pair;
    return a;
}

然后我两次调用这个函数:

first((1, 2));
first(("a", "b"));

编译器将生成两个版本first(),一个专门用于整数对,一个专门用于字符串对。

该名称源自编程语言术语“多态性”——意思是一个函数可以处理多种类型的数据。单态化是从多态代码到单态代码的转换。

于 2013-01-07T14:38:14.093 回答
25

不确定是否还有人在看这个,但 Rust 文档实际上确实提到了它是如何通过这个过程实现无成本抽象的。从使用泛型的代码性能

您可能想知道在使用泛型类型参数时是否存在运行时成本。好消息是,Rust 以这样一种方式实现泛型,即使用泛型类型的代码运行速度不会比使用具体类型慢。

Rust 通过在编译时对使用泛型的代码执行单态化来实现这一点。单态化是通过填充编译时使用的具体类型将通用代码转换为特定代码的过程。

在这个过程中,编译器执行的步骤与我们在示例 10-5 中创建泛型函数的步骤相反:编译器查看调用泛型代码的所有位置,并为调用泛型代码的具体类型生成代码.

让我们通过一个使用标准库的 Option 枚举的示例来看看它是如何工作的:

let integer = Some(5);
let float = Some(5.0);

当 Rust 编译这段代码时,它会执行单态化。在此过程中,编译器读取已在 Option 实例中使用的值,并识别出两种 Option:一种是 i32,另一种是 f64。因此,它将 Option 的通用定义扩展为 Option_i32 和 Option_f64,从而将通用定义替换为特定定义。

代码的单态化版本如下所示。通用选项被编译器创建的特定定义替换:

// Filename: src/main.rs

enum Option_i32 {
    Some(i32),
    None,
}

enum Option_f64 {
    Some(f64),
    None,
}

fn main() {
    let integer = Option_i32::Some(5);
    let float = Option_f64::Some(5.0);
}

因为 Rust 将泛型代码编译为指定每个实例中的类型的代码,所以我们无需为使用泛型支付运行时成本。当代码运行时,它的执行就像我们手动复制每个定义一样。单态化的过程使得 Rust 的泛型在运行时非常高效。

于 2018-11-07T15:52:41.243 回答
4

对此不确定;你能链接到谈话吗?这可能是一句随口一说。

Herman 可能创造了一个类似模板专业化的术语,它从模板生成相互不相关(非多态或“单态”)的类型/对象,这是一个多态结构。

于 2013-01-07T03:55:56.513 回答
4

Rust Book中有一个很好的关于单态化的解释

单态化是通过填充编译时使用的具体类型将通用代码转换为特定代码的过程。

从书中的例子中,如果你定义了变量Some

let integer = Some(5);
let float = Some(5.0);

当 Rust 编译这段代码时,它会执行单态化。在该过程中,编译器读取实例中已使用的值Option<T> 并识别两种类型Option<T>:一种 is i32,另一种 is f64。因此,它扩展了Option<T>into Option_i32和的通用定义Option_f64,从而将通用定义替换为特定定义。

代码的单态化版本如下所示。泛型 Option<T>被编译器创建的特定定义替换:

文件名:src/main.rs

enum Option_i32 {
    Some(i32),
    None,
}

enum Option_f64 {
    Some(f64),
    None,
}

fn main() {
    let integer = Option_i32::Some(5);
    let float = Option_f64::Some(5.0);
}
于 2020-03-25T20:05:31.907 回答