Область действия 'let' с затенением и преобразованием String -> & str - PullRequest
0 голосов
/ 07 марта 2019

С помощью следующего кода я попытался вернуть & 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 ]

1 голос
/ 07 марта 2019

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.Вы можете сделать что-то вроде этого, если вы хотите иметь проверенный 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 - Почему нам не нужно явно указывать <f32> в temp.trim().parse()

Это выводится компилятором.

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 голос
/ 07 марта 2019

Что касается вопроса 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 в этом случае, которому принадлежат данные.

0 голосов
/ 08 марта 2019

В вашей программе 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 является заимствованной ссылкой. Вы не можете вернуть заимствованную ссылку на локальную переменную, которая будет освобождена при возврате функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...