» Rust快速入门 » 2. 高级篇 » 2.3 泛型

泛型

泛型主要解决如何将类型和功能推广到更广泛场景的问题。

例如,定义一个名为 foo泛型函数,它接受任何类型的参数 T

fn foo<T>(arg: T) { ... }

函数

struct A;          // 具体类型 `A`。
struct SGen<T>(T); // 泛型类型 `SGen`。

// 定义一个函数 `gen_spec_t`,它接受类型为 `SGen<T>` 的参数 `_s`。
// 它已经明确给出了自定义的具体类型参数 `A`,`A` 不是泛型类型参数,因此它不是泛型的。
fn gen_spec_t(_s: SGen<A>) {}

// 定义一个函数 `gen_spec_i32`,它接受类型为 `SGen<i32>` 的参数 `_s`。
// 它已经明确给出了类型参数 `i32`,这是一个具体类型。
// 因为 `i32` 不是一个泛型类型,所以这个函数也不是泛型的。
fn gen_spec_i32(_s: SGen<i32>) {}

// 定义一个函数 `generic`,它接受类型为 `SGen<T>` 的参数 `_s`。
// 因为 `SGen<T>` 前面带有 `<T>`,所以这个函数对 `T` 泛型。
fn generic<T>(_s: SGen<T>) {}

fn main() {
    // 使用非泛型函数
    gen_spec_t(SGen(A));   // 隐式指定类型参数 `A`。
    gen_spec_i32(SGen(6)); // 隐式指定类型参数 `i32`。

    // 显式指定类型参数 `char` 给 `generic()`。
    generic::<char>(SGen('a'));

    // 隐式指定类型参数 `char` 给 `generic()`。
    generic(SGen('c'));
}

实现

struct S<T> {
    v: T,
}

impl<T> S<T> {
    fn value(&self) -> &T {
        &self.v
    }
}

fn main() {
    let a = S { v: 58i32 };
    println!("{}", a.value());
}

特征

traits 也可以是泛型的。

// 用泛型类型参数 `T` 定义一个名为 `Printable` 的泛型特征
trait Printable<T> {
    // 用于获取自身引用并返回类型为 `T` 的值的方法 `print`
    fn print(&self) -> T;
}

// 为 `i32` 类型实现 `Printable` 特征
impl Printable<String> for i32 {
    // 为 `print` 方法实现将整数转换为字符串的逻辑
    fn print(&self) -> String {
        self.to_string()
    }
}

// 为 `bool` 类型实现 `Printable` 特征
impl Printable<&'static str> for bool {
    // 为 `print` 方法实现返回 "true" 或 "false" 的字符串切片的逻辑
    fn print(&self) -> &'static str {
        if *self {
            "true"
        } else {
            "false"
        }
    }
}

fn main() {
    let number = 58;
    let number_str = number.print();
    println!("Printed number: {}", number_str);

    let boolean = true;
    let boolean_str = boolean.print();
    println!("Printed boolean: {}", boolean_str);
}

Bounds (限定)

在使用泛型时,类型参数通常需使用特征作为限定,以规定类型实现的功能。 例如,以下示例使用特征 Display 打印,因此它要求 T 被限制为 Display;也就是说,T 必须实现 Display

fn printer<T: Display>(t: T) {
    println!("{}", t);
}

多重限定

可以使用 + 对单个类型应用多个限定。

// 定义一个名为 `Printable` 的特征
trait Printable {
    fn print(&self);
}

// 定义一个名为 `Debuggable` 的特征
trait Debuggable {
    fn debug(&self);
}

// 一个泛型函数,接受实现 `Printable` 和 `Debuggable` 特征的参数
fn print_and_debug<T: Printable + Debuggable>(item: T) {
    item.print();
    item.debug();
}

Where 子句

可以使用 where 子句在左花括号 { 之前表达限定。此外,where 子句可以将限定应用于任意类型,而不仅仅是输入参数的类型。

impl <A: TraitB + TraitC, D: TraitE + TraitF> MyTrait<A, D> for YourType {}

// Expressing bounds with a `where` clause
impl <A, D> MyTrait<A, D> for YourType where
    A: TraitB + TraitC,
    D: TraitE + TraitF {}

使用 "where 子句",前面 print_and_debug 的示例可以转换为这样:

trait Printable {
    fn print(&self);
}

trait Debuggable {
    fn debug(&self);
}

fn print_and_debug<T>(item: T)
where
    T: Printable + Debuggable,
{
    item.print();
    item.debug();
}

struct Data;

impl Printable for Data {
    fn print(&self) {
        println!("Printing");
    }
}

impl Debuggable for Data {
    fn debug(&self) {
        println!("Debugging");
    }
}

fn main() {
    let data = Data;
    print_and_debug(data);
}

关联类型

关联类型 是对 trait 泛型的扩展,它允许 trait 在内部定义新项。

// 定义一个名为 `Container` 的特征,并带有关联类型 `Item` 
trait Container {
    type Item;

    // 返回关联类型的实例的方法
    fn first(&self) -> Self::Item;
}

impl Container for Vec<i32> {
    // 指定关联类型 `Item` 为 `i32`
    type Item = i32;

    fn first(&self) -> Self::Item {
        self[0]
    }
}

impl Container for Vec<String> {
    // 指定关联类型 `Item` 为 `String`
    type Item = String;

    fn first(&self) -> Self::Item {
        self[0].clone()
    }
}

代码挑战

尝试修改编辑器中提供的泛型代码以打印:

Item from int vector: 58
Item from str vector: literank.cn
Loading...
> 此处输出代码运行结果
上页
下页