阴影和字符串 -> &str 转换的'let'范围



使用以下代码,我试图返回用户输入的温度&str,但徒劳无功。然后,我试图返回 f32,但仍然在挣扎......

问题 1.我在底部收到错误的原因是因为"let temp = String::new();"的范围仍然存在,即使我稍后在循环中通过"let temp = temp.trim().parse::<f32>();"来"影子"它?

问题 2.如何重写代码以使其返回 &str?

fn gettemp() -> f32 {
let temp = String::new();
loop {
println!("What is your temperature?");
io::stdin().read_line(&mut temp).expect("Failed to read the line");
let temp = temp.trim().parse::<f32>();
if !temp.is_ok() {
println!("Not a number!");
} else {
break;
}
}
temp
}

错误:

error[E0308]: mismatched types
--> src/main.rs:70:5
|
49 | fn gettemp() -> f32 {
|                 --- expected `f32` because of return type
...
70 |     temp
|     ^^^^ expected f32, found struct `std::string::String`
|
= note: expected type `f32`
found type `std::string::String`

A1 - 不,这不是阴影的工作方式。让我们看一下带有注释的代码。

fn gettemp() -> f32 {
let temp = String::new(); // Outer
loop {
// There's no inner temp at this point, even in the second
// loop pass, etc.
println!("What is your temperature?");
// Here temp refers to the outer one (outside of the loop)
io::stdin().read_line(&mut temp).expect("Failed to read the line");
// Shadowed temp = let's call it inner temp
let temp = temp.trim().parse::<f32>();
//    ^      ^
//    |      |- Outer temp
//    |- New inner temp
// temp refers to inner temp
if !temp.is_ok() {
println!("Not a number!");
} else {
// Inner temp goes out of scope
break;
}
// Inner temp goes out of scope
}
// Here temp refers to outer one (String)
temp
}

A2 - 您无法返回&str. @E_net4发布了一个指向答案的链接。但是,您可以返回String。你可以做一些像这样的事情 nn 案例,你想要一个经过验证的String

fn gettemp() -> String {
loop {
println!("What is your temperature?");
let mut temp = String::new();
io::stdin()
.read_line(&mut temp)
.expect("Failed to read the line");
let trimmed = temp.trim();
match trimmed.parse::<f32>() {
Ok(_) => return trimmed.to_string(),
Err(_) => println!("Not a number!"),
};
}
}

我在您的代码中看到其他几个问题。

let temp = String::new();

应该let mut temp,因为您想稍后借用可变引用(&mut tempread_line调用中)。

另一个问题是loopread_lineread_line追加到String。运行此代码...

let mut temp = "foo".to_string();
io::stdin().read_line(&mut temp).unwrap();
println!("->{}<-", temp);

。,例如输入10。您将看到以下输出...

->foo10
<-

。这不是你想要的。我会以这种方式重写gettemp()

fn gettemp() -> f32 {
loop {
println!("What is your temperature?");
let mut temp = String::new();
io::stdin()
.read_line(&mut temp)
.expect("Failed to read the line");
match temp.trim().parse() {
Ok(temp) => return temp,
Err(_) => println!("Not a number!"),
};
}
}

恕我直言,显式return temp更清晰和可读(与建议的用值脱离循环相比)。


A3 - 为什么我们不需要在temp.trim().parse()中明确说明<f32>

它由编译器推断。

fn gettemp() -> f32 { // 1. f32 is return type
loop {
println!("What is your temperature?");
let mut temp = String::new();
io::stdin()
.read_line(&mut temp)
.expect("Failed to read the line");
match temp.trim().parse() {
// 4. parse signature is pub fn parse<F>(&self) -> Result<F, ...>
//    compiler knows it must be Result<f32, ...>
//    Result<f32, ...> = Result<F, ...> => F = f32
//    F was inferred and there's no need to explicitly state it
Ok(temp) => return temp,
//  |                |
//  |      2. return type is f32, temp must be f32
//  |
//  | 3. temp must be f32, the parse result must be Result<f32, ...>            
Err(_) => println!("Not a number!"),
};
}
}

关于问题 1,您可以使用一个值break出循环:

fn gettemp() -> f32 {
let mut temp = String::new();
loop {
println!("What is your temperature?");
io::stdin().read_line(&mut temp).expect("Failed to read the line");
let temp = temp.trim().parse::<f32>();
if !temp.is_ok() {
println!("Not a number!");
} else {
break temp.unwrap() // yield value when breaking out of loop
}
}
}

这样,整个循环的值就是您随break传递的东西。

关于问题2,我不确定你是否真的想这样做,因为&str是借用的类型。我认为在这种情况下,您想返回一个拥有数据的String

在程序中,loop { ... }创建一个新作用域。第二个temp的范围从定义它的地方开始,到loop结束时结束。请参阅以下示例:

fn main() {
let a = 1;
{
let a = 2;
println!("{}", a);
}
println!("{}", a);
}

这打印 2, 1。

如果要返回一个字符串,请使用(代码根据下面的注释固定):

fn gettemp() -> String {
loop {
let mut temp = String::new();
println!("What is your temperature?");
std::io::stdin().read_line(&mut temp).expect("Failed to read the line");
temp = temp.trim().to_string();
match temp.parse::<f32>() {
Err(_) => println!("Not a number!"),
_ => return temp,
}
}
}

&str是借用的参考资料。您不能返回对局部变量的借用引用,该变量将在函数返回时释放。

最新更新