A1 - nope, that's not how shadowing works. Let's look at your code with comments.
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 - you can't return &str
. @E_net4 posted a link to the answer why. However, you can return String
. You can do something like this nn case you'd like to have a validated 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!"),
};
}
}
I see couple of another problems in your code.
let temp = String::new();
Should be let mut temp
, because you'd like to borrow mutable reference later (&mut temp
in the read_line
call).
Another issue is the loop
& read_line
. read_line
appends to the String
. Run this code ...
let mut temp = "foo".to_string();
io::stdin().read_line(&mut temp).unwrap();
println!("->{}<-", temp);
... and enter 10
for example. You'll see following output ...
->foo10
<-
... which is not what you want. I'd rewrite gettemp()
in this way:
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!"),
};
}
}
IMHO explicit return temp
is much cleaner & readable (compared to suggested break out of the loop with a value).
A3 - Why we don't need to explicitly state <f32>
in temp.trim().parse()
It's inferred by the compiler.
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!"),
};
}
}