Rust 中的泛型参数及其在内部项目中的使用规则

在探讨 Rust 中泛型参数在内部项目中的使用规则之前,我们首先来看看官方是如何解释这个问题的:

Inner items do not inherit type or const parameters from the functions they are embedded in.

换句话说,内部项目不会从它们嵌套的函数中继承类型或常量参数。

以下是一些错误的代码示例:

fn foo(x: T) {
    fn bar(y: T) { // 这里的 T 是在"外部"函数中定义的
        // ..
    }
    bar(x);
}

这种写法也不行:

fn foo(x: T) {
    type MaybeT = Option;
    // ...
}

还有这种:

fn foo(x: T) {
    struct Foo {
        x: T,
    }
    // ...
}

简而言之,函数内部的项目基本上就像顶层项目一样,只是它们只能在所在的函数中使用。 针对这个问题,有几种解决方案。

如果项目是一个函数,你可以使用闭包:

fn foo(x: T) {
    let bar = |y: T| { // 显式类型注解可能不是必需的
        // ..
    };
    bar(x);
}

还可以直接复制泛型参数参数:

fn foo(x: T) {
    fn bar(y: T) {
        // ..
    }
    bar(x);
}
fn foo(x: T) {
    type MaybeT = Option;
}

同时确保复制所有的Bound:

fn foo(x: T) {
    fn bar(y: T) {
        // ..
    }
    bar(x);
}
fn foo(x: T) {
    struct Foo {
        x: T,
    }
}

如果项目是 impl 中的一个函数,定义一个私有辅助函数可能更为简单:

impl Foo {
    pub fn foo(&self, x: T) {
        self.bar(x);
    }

    fn bar(&self, y: T) {
        // ..
    }
}

总结

在 Rust 中,函数、结构体定义和 type 定义被视为顶层项目(top items),除了它们只能在定义的范围内使用外,没有其他区别。简而言之,在定义泛型函数、结构体和 type 定义时,只需再定义一次泛型参数即可。 例如:

fn foo(x: T) {
    fn bar(y: T) { // T 是在"外部"函数中定义的
        // ..
    }
    bar(x);
}

修改为:
fn foo(x: T) {
    fn bar(y: T) { // 注意这里的区别
        // ..
    }
    bar(x);
}