rust 我把一个字符串转换成浮点数,我怎么验证它是一个f64?

wvt8vs2t  于 2023-04-21  发布在  其他
关注(0)|答案(2)|浏览(216)

我有个很奇怪的疑问
我正在学习rust编程书,在一个章节中,他们建议做一个温度转换器......我实际上做了,问题是我不明白为什么工作。
主要问题出现在我试图复制一段代码时,这段代码允许我比较用户引入的值是否是浮点类型。
当我把代码,我试图编译我得到下一个错误。

Compiling enums v0.1.0 (C:\Users\ruben\Proyectos\Rust\the_rust_programming_language\enums)
error[E0308]: mismatched types
  --> src\main.rs:96:35
   |
96 |           Err(parse_float_error) => {
   |  ___________________________________^
97 | |             println!("Please input a valid value. _{}_", parse_float_error);
98 | |         }
   | |_________^ expected `f64`, found `()`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `enums` due to previous error

这是生成错误的代码:

use std::io;

fn user_input() -> String {
    let mut user_input: String = String::new();
    io::stdin()
        .read_line(&mut user_input)
        .expect("Failed to read line");
    return user_input;
}
fn main() {
    let fahrenheit: f64 = match user_input().trim().parse() {
        Ok(f64) => f64,
        Err(parse_float_error) => {
            println!("Please input a valid value. _{}_", parse_float_error);
        }
    };
}

The working full version of the temperature converter could be find here

***最有可能的是,必须有一个更好的方法来构建代码,所以如果你们中的一些人有建议,我很乐意阅读它。

我知道问题是enum类型的,问题是我真的不知道enums是如何工作的。
对我来说,以一种简单的方式,当一段数据是enum中可用的一种或另一种数据时,使用enum,我得到了一个帮助我以这种方式理解它的例子:枚举。问题是我真的,真的不明白它,这本书也没有帮助。
我知道这是一个非常普遍的问题,但如果有人有一个北方遵循它会有很大帮助。
谢谢你。

3vpjnl9f

3vpjnl9f1#

对我来说,用一种简单的方式,当一段数据是枚举中可用的一种或另一种时,就使用枚举
大多数情况下,枚举可以有一个或多个变体,并且每个变体可以(但不是必须)有关联的数据。每个变体的数据类型可以相同或不同。
result枚举具体有两个变体。Ok变体表示操作成功。Err变体表示存在错误。result是泛型类型,它有两个类型参数,T表示预期结果的类型,E表示错误的类型。
在这一点上值得注意的是,在rust中推断类型的方式与C、C和许多其他流行语言有很大的不同。在C/C中确定表达式类型的过程是从表达式的最里面部分向外流动的。每个函数调用或操作符都是基于其参数的类型来选择的,并确定其结果的类型。这反过来又成为下一步向外的参数。相比之下,在Rust中,类型推断可以在两个方向上运行。表达式中的类型可以,而且经常是,从您对结果所做的事情中推断出来的。
match表达式允许您分解枚举,并根据您拥有的变量采取不同的操作。
考虑到所有这些,让我们分解您的代码。

let fahrenheit: f64 =

我们声明了一个名为fahrenheit的变量,并显式地告诉编译器它的类型。当编译器试图解释表达式时,这个类型将驱动类型检查和推理。

match

我们开始匹配表达式。

user_input()

我们调用一个函数,该函数在任何方面都不是泛型的,因此编译器可以使用另一种类型String

.trim()

我们在String上调用trim方法。同样,这不是泛型,所以我们又有了一个固定的类型&str

.parse()

这里是事情变得更有趣的地方,“parse”是一个泛型函数。它返回一个result,但result的泛型参数不是固定的,它们必须从用户对结果的操作和parse签名中的限制来推断。

Ok(f64) => f64,

如果结果是Ok,我们将值展开并返回它。这里使用f64有点不合适,它看起来像一个类型名,但实际上更像一个变量名。如果您编写了Ok(v) => v,,您的代码将表现相同,并且更符合习惯
无论如何,表达式的这一部分让类型推断完成它的工作。您已经匹配了Ok变体并将结果视为f64。因此T必须是f64。将其与parse的签名和f64FromStr的实现相结合,意味着E必须是ParseFloatError

Err(parse_float_error) => {
        println!("Please input a valid value. _{}_", parse_float_error);
    }

这就是我们出错的地方。我们已经打印了一个错误消息,但我们实际上还没有处理这个错误!我们仍然有一个需要f64的表达式,而我们没有!我们需要以一种方式来处理这个错误,要么给我们一个有效的f64,要么向编译器承诺它不需要一个。
有几种方法可以做到这一点。

  • 您可以选择一个默认值(如Paul的答案)0.0f64
  • 你可能会恐慌panic!("foo {}",parse_float_error)
  • 你可以调用一个承诺永远不会正常返回的函数,例如abort()
  • 您可以从函数return返回
  • 如果您的代码在循环中,则可以使用循环控制结构breakcontinue
  • 如果你绝对肯定错误永远不会发生,你可以告诉编译器它们永远不会发生。如果你告诉编译器某些事情永远不会发生,但它还是发生了,那就是未定义的行为!在这种情况下,这是绝对不合适的,但我为了完整性而包含它unsafe { std::hint::unreachable_unchecked() }

你必须选择其中之一,然后做。

lnvxswe2

lnvxswe22#

检查字符串是否表示浮点值的最好方法是解析它,这是你的代码正在做的。解析用户输入本身就充满了错误情况,所以你不可避免地要执行大量的错误处理,因为Rust的设计/本质迫使你处理错误。
你的代码真实的是编译器错误。你的let... match arm返回不同的类型:f64()(单元结构体),就像错误消息说的那样。要解决这个问题,从Err臂返回一个f64,就像Ok臂一样:

...
        Err(parse_float_error) => {
            println!("Please input a valid value. _{}_", parse_float_error);
            0.0f64
        }

相关问题