跳转到内容

Rust 错误 E0425:cannot find value in this scope(找不到值)

E0425 的意思是:Rust 在代码里的某个位置找一个名字,却没有找到。这是最常见的错误之一,好在几乎总能很快修好。原因通常是拼写错误、变量定义在另一个代码块里,或者函数需要写上模块路径。本页是 Rust 编译错误详解系列的一部分。

error[E0425]: cannot find value `total_scor` in this scope
--> src/main.rs:3:33
|
3 | println!("Final score: {}", total_scor);
| ^^^^^^^^^^
|
help: a local variable with a similar name exists
|
3 | println!("Final score: {}", total_score);
| +

“cannot find value total_scor in this scope”的意思是“在这个作用域里找不到值 total_scor”。help 告诉你:“有一个名字相近的局部变量”。

产生这个错误的程序是这样的:

fn main() {
let total_score = 42;
println!("Final score: {}", total_scor);
}

^^^^ 标出的就是 Rust 找不到的名字:第 3 行的 total_scor。“in this scope”(在这个作用域里)指的是“从这一行所在的位置看过去”。Rust 检查了在这个位置能看到的所有变量、函数和导入,没有一个叫这个名字。

help: 那一行也要看。这里 rustc 发现了一个名字很像的变量(total_score),还用 + 标出了少写的那个字母。看到 “a local variable with a similar name exists”(存在一个名字相近的局部变量),基本就是拼错了。

这就像你的朋友叫“张伟”,你却隔着屋子喊“张为!”。他人就在那儿,可没有人会应“张为”这个名字。

如果找不到的名字是你要调用的函数,同一个错误会写成 cannot find function ... in this scope(在这个作用域里找不到函数)。

Rust 在程序运行之前,就要确定每个名字指的是什么。变量只从它的 let 那一行开始存在,到声明它的代码块的右花括号 } 为止,这就是它的作用域(scope)。出了这个范围,这个名字根本就不存在。

很多语言会放过这种错误,等以后才让你发现。在 JavaScript 里,一个拼写错误可能悄悄创建出一个新的全局变量,或者给你一个 undefined。在 Python 里,你会在运行时得到 NameError,而且可能只在测试从没覆盖到的那条代码路径上才出现。Rust 每次都会在编译时把它抓出来。

函数在模块里也遵循同样的道理:mod billing 里的函数,在你写出它的路径或者用 use 把它引入之前,main 是看不到的。

当 help: 那一行说存在名字相近的变量时,就用这个方法。这是到目前为止最常见的原因。Rust 的名字还区分大小写,所以 Total_score 和 total_score 是两个不同的名字。

fn main() {
let total_score = 42;
println!("Final score: {}", total_score);
}

输出:

Final score: 42
▶ 动手试一试

修复 2:在两处都能看到的地方声明变量

Section titled “修复 2:在两处都能看到的地方声明变量”

当 help 提示 “the binding is available in a different scope in the same function”(这个绑定在同一函数的另一个作用域里)时,就用这个方法。你在循环或 if 代码块里创建了变量,却在 } 之后才用它。出错的版本是这样的:

fn main() {
let prices = [120, 300, 80];
for price in prices {
let with_tax = price + price / 10;
println!("{with_tax}");
}
println!("最后一件的含税价:{}", with_tax); // error[E0425]
}

with_tax 在每一轮循环里都会重新创建,到循环的 } 就被扔掉了。如果循环结束后还需要某个值,就在循环之前声明它,在循环里更新它:

fn main() {
let prices = [120, 300, 80];
let mut last_with_tax = 0;
for price in prices {
let with_tax = price + price / 10;
println!("{with_tax}");
last_with_tax = with_tax;
}
println!("最后一件的含税价:{}", last_with_tax);
}

输出:

132
330
88
最后一件的含税价:88
▶ 动手试一试

如果你在 let 那一行之前就用了变量,也是同样的修法。Rust 从上往下读代码,把 let 往上挪就行。

修复 3:写出函数的路径,或者加一行 use

Section titled “修复 3:写出函数的路径,或者加一行 use”

当报错是 cannot find function,而且这个函数在另一个模块里时,就用这个方法。Rust 会打印:

error[E0425]: cannot find function `total_with_tax` in this scope
--> src/main.rs:8:17
|
8 | let total = total_with_tax(50.0);
| ^^^^^^^^^^^^^^ not found in this scope
|
help: consider importing this function
|
1 + use crate::billing::total_with_tax;
|

这里的 help 建议你“导入这个函数”。你可以用完整路径调用它(billing::total_with_tax(50.0)),也可以加上 rustc 建议的那行 use:

mod billing {
pub fn total_with_tax(amount: f64) -> f64 {
amount * 1.2
}
}
use crate::billing::total_with_tax;
fn main() {
let total = total_with_tax(50.0);
println!("{total}");
}

输出:

60
▶ 动手试一试

这个函数还必须是 pub 的。少了它,你会得到另一个错误(E0603,“function is private”,函数是私有的)。路径和 use 的用法见模块。

在方法里,如果找不到的名字是结构体的某个字段,就用这个方法。从 Java 或 C# 转过来的人,很自然地会直接写 count,以为它就是那个字段。在 Rust 里,你必须写 self.count。rustc 会提示:help: you might have meant to use the available field(你可能想用的是这个可用的字段)。

struct Counter {
count: u32,
}
impl Counter {
fn report(&self) {
println!("计数:{}", self.count);
}
}
fn main() {
let c = Counter { count: 3 };
c.report();
}

输出:

计数:3
▶ 动手试一试
  • 在 if 里面创建的变量。 写了 if balance > 50 { let bonus = 10; },再写 println!("{}", bonus) 就会报错,因为 bonus 在 } 那里就没了。修复:让 if 直接产生这个值,let bonus = if balance > 50 { 10 } else { 0 };。

  • 调用构造函数时没写类型。 let p = new("ferris"); 会报 cannot find function `new` in this scope。修复:new 属于类型,所以要写 Player::new("ferris")。

  • 在没有 self 参数的函数里用 self。 这是 E0425 的近亲 E0424:

    error[E0424]: expected value, found module `self`
    --> src/main.rs:7:9
    |
    6 | fn reset() {
    | ----- this function doesn't have a `self` parameter
    7 | self.count = 0;
    | ^^^^ `self` value is a keyword only available in methods with a `self` parameter

    意思是:这个函数没有 self 参数,而 self 只能在带 self 参数的方法里使用。修复:加上 self 参数。rustc 建议用 &self,但这个函数要修改字段,所以需要写成 fn reset(&mut self)。

小测验

1. rustc 提示 "help: a local variable with a similar name exists"。最可能的原因是什么?

2. 你在 for 循环里写了 let found = true;,然后在循环结束后使用 found。为什么会报错?

3. 函数 send 定义在 mod mailer 里。哪一行能让 main 直接用 send() 调用它?

得分: 0 / 3