0Pricing
Learn Rust Coding · 课时

泛型函数

根据类型参数化行为。

泛型函数 是 CoddyKit 上的免费 Learn Rust Coding 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Learn Rust Coding 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Learn Rust Coding 课程共包含 4 节课。

为什么使用泛型函数

泛型函数让您只需编写一个函数,就能处理多种类型,而不必为每种类型复制代码。Rust 会在编译时替换占位类型。

想象一下,您要分别为整数和 chars 编写一个 largest。泛型可以将它们合并为一个定义,而且不会产生运行时开销。

类型参数

泛型函数会在名称后的尖括号中声明类型参数。名称 T 只是一种惯例,但任何 CamelCase 标识符都可以使用。

随后,参数可以出现在参数列表和返回类型中,代表调用者所使用的具体类型。

fn first<T>(pair: (T, T)) -> T {
    pair.0
}

简单的恒等函数

此程序定义了一个泛型 echo,它原样返回传入的参数。它分别使用整数和字符串切片调用了一次。

编译器会为实际使用的每种类型分别生成一个具体版本。

fn echo<T>(value: T) -> T {
    value
}

fn main() {
    println!("{}", echo(42));
    println!("{}", echo("hi"));
}

单态化

Rust 使用单态化:在编译时,它会为使用到的每种具体类型生成函数的专用副本。这里没有装箱或虚拟分派。

因此,泛型代码的运行速度可以与手写的特定类型代码一样快。

泛型需要约束

在泛型函数内部,您只能使用所有可能类型都支持的操作。单独的 T 不能进行加法、比较或打印。

这段代码无法编译,因为 T 可能没有实现比较功能。接下来,我们会使用特征约束修复它。

fn larger<T>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

添加特征约束

要比较值,请使用 PartialOrd 约束 T。该约束保证类型支持 > 运算符。

我们还添加 Copy,这样对于整数等简单类型,就可以返回值而不会遇到移动问题。

fn larger<T: PartialOrd + Copy>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

调用受约束的函数

现在,该函数适用于实现了这两个特征的任何类型。整数和浮点数都满足 PartialOrd + Copy。

同一份源代码会被单态化为两个版本,并为每次调用输出结果。

fn larger<T: PartialOrd + Copy>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

fn main() {
    println!("{}", larger(3, 9));
    println!("{}", larger(2.5, 1.0));
}

多个类型参数

函数可以声明多个类型参数。每个参数彼此独立,因此两个参数可以使用不同的类型。

这里的 pair 接受任意 T 和任意 U,并将它们作为元组返回。

fn pair<T, U>(a: T, b: U) -> (T, U) {
    (a, b)
}

打印泛型值

要使用 {} 打印泛型值,该类型必须实现 Display。我们添加这个约束,以便传入任何可打印的类型。

这段代码会为值添加标签并返回它,展示了一个纯粹用于格式化的约束。

use std::fmt::Display;

fn announce<T: Display>(label: &str, value: T) {
    println!("{}: {}", label, value);
}

fn main() {
    announce("count", 7);
    announce("name", "Ada");
}

涡轮鱼语法

有时,编译器无法仅根据参数推断出 T。涡轮鱼 ::<Type> 允许您在调用位置明确指定它。

当返回类型不明确时,这种语法最常用于 parse 和 collect 等方法。

fn main() {
    let n = "42".parse::<i32>().unwrap();
    println!("{}", n + 1);
}

引用上的泛型

泛型参数同样适用于引用。通过引用进行约束,可以在只需读取值时避免要求 Copy。

这个类似 longest_str 的辅助函数借用两个切片,并返回其中一个,而不会取得所有权。

fn pick<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> &'a T {
    if a > b { a } else { b }
}

快速检查

测试您对 Rust 泛型函数的理解。

回顾

泛型函数使用尖括号中的类型参数,通过单态化以零运行时开销处理多种类型。

对泛型类型执行操作需要 PartialOrd、Copy 或 Display 等特征约束。当推断无法确定类型时,请使用涡轮鱼。

常见问题解答

「泛型函数」课时是免费的吗?

是的 — 「泛型函数」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Learn Rust Coding 课程的其余内容,请升级到 CoddyKit PRO。 Learn Rust Coding 课程共包含 4 节课。

「泛型函数」这节课中我会学到什么?

根据类型参数化行为。 你通过在浏览器中直接运行的动手代码来练习 Learn Rust Coding,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Learn Rust Coding 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Learn Rust Coding 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「泛型函数」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Learn Rust Coding 课中编写并运行代码吗?

能。每节 Learn Rust Coding 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 泛型函数
  2. 泛型结构体和枚举
  3. 特征约束
  4. where 子句与多重约束
← 返回 Learn Rust Coding