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

时间:2019-03-07 11:45:50

标签: rust

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

Q1。之所以在底部显示错误,是因为'let temp = String::new();'的范围仍然存在,即使我稍后在循环中通过'let temp = temp.trim().parse::<f32>();'对其进行“阴影化”?

Q2。我该如何重写代码,使其返回&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`

3 个答案:

答案 0 :(得分:1)

关于问题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

答案 1 :(得分:1)

A1-不,这不是阴影的工作原理。让我们看看带有注释的代码。

package Lab5;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashSet;
import java.util.Scanner;

public class Lorem {

    public static void main(String[] args) {
        String[] loremIpsum = null;
        try {
            loremIpsum = new Scanner(new File("loremIpsum.txt")).next().split(" ");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        System.out.println(loremIpsum.length);
        HashSet h = new HashSet();

        for(int i=0;i<loremIpsum.length;i++) {
            String word=loremIpsum[i];
            System.out.println(word);
            if(h.contains(word)) {
                System.out.println("we found a duplicate");
            } else {
                h.add(word);
            }   
        }

    }

}

A2-您无法返回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 } 。 @ E_net4发布了答案的链接。但是,您可以返回&str。您可以执行以下操作,以使String经过验证:

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_lineloopread_line追加到read_line。运行此代码...

String

...,然后输入let mut temp = "foo".to_string(); io::stdin().read_line(&mut temp).unwrap(); println!("->{}<-", temp); 。您将看到以下输出...

10

...这不是您想要的。我将以这种方式重写->foo10 <-

gettemp()

IMHO显式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!"), }; } } 更清晰易读(与建议使用一个值冲破循环相比)。


A3-为什么我们不需要在return temp中明确声明<f32>

由编译器推断。

temp.trim().parse()

答案 2 :(得分:0)

在您的程序中,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是借用的参考。您不能返回借用的对局部变量的引用,该引用将在函数返回时释放。