使用以下代码,我试图返回用户输入的温度&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 temp
在read_line
调用中)。
另一个问题是loop
和read_line
。read_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
是借用的参考资料。您不能返回对局部变量的借用引用,该变量将在函数返回时释放。