Rust 错误 E0411:cannot find type Self in this scope(在 impl 外使用 Self)
E0411 的意思是:你在 Rust 看不出 Self 指什么的地方写了 Self。Self 是“这个 impl 块(或 trait)所针对的类型”的简写,所以它只能用在 impl、trait 或类型定义里面。最常见的原因是把 fn new() -> Self 这样的构造函数写在了文件顶层,或者把一个方法从它的 impl 块里复制了出来。这个错误很常见,改起来也快。和 E0412 不同(它从 Rust 1.93 起变成了 E0425),这个错误码没有变:rustc 1.97 报的仍然是 E0411。这个系列的其他错误,请看 Rust 编译错误详解。
error[E0411]: cannot find type `Self` in this scope --> src/main.rs:5:21 |5 | fn new_counter() -> Self { // ❌ 在 `impl` 外面用了 `Self` | ----------- ^^^^ `Self` is only available in impls, traits, and type definitions | | | `Self` not allowed in a function第一行的意思是“在这个作用域里找不到类型 Self”。
产生这个错误的程序是这样的:
struct Counter { count: u32,}
fn new_counter() -> Self { // ❌ 在 `impl` 外面用了 `Self` Counter { count: 0 }}
fn main() { let c = new_counter(); println!("{}", c.count);}这个错误是什么意思
Section titled “这个错误是什么意思”rustc 在第 5 行指出了两处:
Self下面的^^^^:“Selfis only available in impls, traits, and type definitions”(Self只能用在 impl、trait 和类型定义里)。规则就这一句话。new_counter下面的-----:“Selfnot allowed in a function”(函数里不允许用Self)。这就是这里出错的原因:new_counter是一个普通函数,不属于任何impl。
你也许知道 new_counter 返回的是 Counter,因为你刚写了 Counter { count: 0 }。但 Rust 不会去读函数体来猜 Self 是什么。Self 的含义只来自包住它的 impl Counter { ... } 或 trait ... { ... },而这里一个都没有。
这就像便利贴上写着“这里”。在地图上,“你在这里”是有意义的;可一张随手放在餐桌上的便利贴,谁也不知道“这里”是哪里。
Rust 为什么要这样做
Section titled “Rust 为什么要这样做”Self 本身不是一个类型,而是一个占位符,由每个 impl 或 trait 来填上:在 impl Counter 里,Self 就是 Counter;在 impl Timer 里,它就是 Timer;在 trait 里,它表示“实现这个 trait 的那个类型”。这正是它好用的地方:你给结构体改名,或者把方法复制到另一个 impl 里,Self 都会跟着变。
普通函数不属于任何类型,所以没有东西可以填进去。Rust 本可以试着从函数体里猜,但那样一来,函数签名就要依赖函数体里的代码了,而 Rust 有意只凭签名本身来检查签名。fn new() -> Self 通常该放在哪里,见结构体。
修复 1:把函数挪进 impl 块
Section titled “修复 1:把函数挪进 impl 块”大多数时候选这个方法。创建某个类型、或者围绕某个类型工作的函数,本来就该放在这个类型的 impl 块里,在那里 Self 会按你预期的那样工作。用 Counter::new() 来调用它:
struct Counter { count: u32,}
impl Counter { fn new() -> Self { Self { count: 0 } }
fn increment(&mut self) { self.count += 1; }}
fn main() { let mut c = Counter::new(); c.increment(); c.increment(); println!("{}", c.count);}输出:
2在 impl 里面,Self 既可以当类型用(-> Self),也可以用来构造值(Self { count: 0 })。参见结构体。
修复 2:把 Self 换成类型名
Section titled “修复 2:把 Self 换成类型名”如果这个函数应该保持为普通函数,比如一个要构造好几种类型的辅助函数,或者它放在另一个模块里,就选这个方法。在你写 Self 的地方,直接写出真正的类型 Counter:
struct Counter { count: u32,}
fn new_counter(start: u32) -> Counter { Counter { count: start }}
fn reset(c: &mut Counter) { c.count = 0;}
fn main() { let mut c = new_counter(10); println!("{}", c.count); reset(&mut c); println!("{}", c.count);}输出:
100从 impl 里复制出来的 fn reset(c: &mut Self) 也用这个方法修:签名和函数体里的每个 Self 都改成 Counter。
修复 3:如果你想表达“任意类型”,就用泛型
Section titled “修复 3:如果你想表达“任意类型”,就用泛型”如果你用 Self 想表达的是“调用者想要的任意类型”,那该用泛型 T,而不是 Self。声明 <T>,并写上函数需要的 trait。这里的 T: Default 让函数能为任意类型创建一个初始值:
fn fresh_pair<T: Default>() -> (T, T) { (T::default(), T::default())}
fn main() { let numbers: (u32, u32) = fresh_pair(); let words: (String, String) = fresh_pair(); println!("{:?}", numbers); println!("{:?}", words);}输出:
(0, 0)("", "")如果你想让每个类型自己决定怎么构造,就把函数放进一个 trait:trait Reset { fn fresh() -> Self; }。在 trait 里,Self 表示“实现它的那个类型”。参见泛型和 trait。
在 main 或普通函数里写 Self { ... }。 let c = Self { count: 0 }; 也会报 E0411,只是标题稍有不同:cannot find struct, variant or union type `Self` in this scope。修复:写成 Counter { count: 0 },或者调用 Counter::new()。
方法里嵌套的辅助函数。 在 impl Counter 里,如果某个方法内部又定义了自己的 fn helper() -> Self,你会得到另一个错误码 E0401:can't use `Self` from outer item(不能使用外层项的 Self)。函数里面的函数不会继承外层的 impl。修复:在内层函数里写 Counter,或者改用闭包,或者把 helper 挪到 impl 里,作为一个独立的方法。
把 Self 和 self 搞混。 大写的 Self 是类型;小写的 self 是调用方法时的那个值。在方法外面用 self 是另一个错误,E0424。两者的修复方法相同:确认代码放在了正确的 impl 块里。
- E0424:在方法外面用了
self(小写,表示值)。 - E0425:找不到某个普通名字的值、函数,或者(从 Rust 1.93 起)类型。
- E0412:“cannot find type”(找不到类型)的旧错误码,现在报为 E0425。
- E0405:找不到某个 trait,通常是少了一行
use。 - E0401:在嵌套函数里用了外层
impl的Self,见上文。 - 所有编译错误:错误页面的完整列表。
小测验
1. 在哪里可以把 Self 当类型用?
2. 顶层的 fn make_user() -> Self 报了 E0411。通常怎么修?
3. 在 impl Counter 里,Self { count: 0 } 创建的是什么?
得分: 0 / 3
- E0411 — Rust error codes index(英文):官方解释
Self代表什么,以及为什么它只能用在 impl、trait 或类型定义里。 - 方法语法 — Rust 程序设计语言:像
fn square(size: u32) -> Self这样的关联函数,以及Self在impl里怎样工作。 - The
Selfkeyword — 标准库文档(英文):Self在 impl、trait 和类型定义里分别表示什么。 Selfin paths — The Rust Reference(英文):精确的规则,包括为什么嵌套的项不能使用外层的Self。