【问题标题】:How to read an integer input from the user in Rust 1.0?如何在 Rust 1.0 中读取用户输入的整数?
【发布时间】:2015-08-02 00:37:31
【问题描述】:

我找到的现有答案都是基于from_str(例如Reading in user input from console once efficiently),但显然from_str(x) 在Rust 1.0 中已更改为x.parse()。作为一个新手,考虑到这种变化,应该如何调整原始解决方案并不明显。

从 Rust 1.0 开始,从用户那里获取整数输入的最简单方法是什么?

【问题讨论】:

    标签: input integer rust user-input


    【解决方案1】:

    这是一个包含所有可选类型注释和错误处理的版本,可能对像我这样的初学者有用:

    use std::io;
    
    fn main() {
        let mut input_text = String::new();
        io::stdin()
            .read_line(&mut input_text)
            .expect("failed to read from stdin");
    
        let trimmed = input_text.trim();
        match trimmed.parse::<u32>() {
            Ok(i) => println!("your integer input: {}", i),
            Err(..) => println!("this was not an integer: {}", trimmed),
        };
    }
    

    【讨论】:

    • unwrap() 的使用怎么样?你如何处理解析错误,并将它们报告给标准错误?
    • @zero_cool 使用match 处理parse() 产生的Result 会报告错误。 unwrap() 会导致程序崩溃。
    【解决方案2】:

    可能最简单的部分是使用text_io crate 并写:

    #[macro_use]
    extern crate text_io;
    
    fn main() {
        // read until a whitespace and try to convert what was read into an i32
        let i: i32 = read!();
        println!("Read in: {}", i);
    }
    

    如果您需要同时读取多个值,则可能需要每晚使用 Rust。

    另见:

    【讨论】:

    • 如果您一次只需要读取一个值,我认为它确实可以稳定运行。
    • text_io dev 在这里。 @VladimirMatveev 是对的,text_io 运行稳定,如果您不读取元组,但每个 read!() 调用只有一个值。它实际上需要 nightly 多个值。我会更新 github 描述。
    • 现在有更好的选择吗?在 Rust 出现 3 年后,我认为会有更好的方法将值输入整数变量。建议的解决方案是我在 rust book 中遇到的,但它很长,而且输入起来感觉有点矫枉过正。 text_io 的建议很棒,但在使用 read!() 之前我无法从函数中打印语句
    • @joe_04_04 “在使用 read!() 之前从函数中打印语句是什么意思?
    • @DanielFath,如果我在尝试使用来自text_ioread!() 之前使用println!(),那么应该从println!() 打印的项目直到read!() 方法之后才会打印.
    【解决方案3】:

    这里有一些可能性(Rust 1.7):

    use std::io;
    
    fn main() {
        let mut n = String::new();
        io::stdin()
            .read_line(&mut n)
            .expect("failed to read input.");
        let n: i32 = n.trim().parse().expect("invalid input");
        println!("{:?}", n);
    
        let mut n = String::new();
        io::stdin()
            .read_line(&mut n)
            .expect("failed to read input.");
        let n = n.trim().parse::<i32>().expect("invalid input");
        println!("{:?}", n);
    
        let mut n = String::new();
        io::stdin()
            .read_line(&mut n)
            .expect("failed to read input.");
        if let Ok(n) = n.trim().parse::<i32>() {
            println!("{:?}", n);
        }
    }
    

    这些使您无需依赖额外的库即可进行模式匹配。

    【讨论】:

    • 来吧,明显不一样,完整的答案让读者更轻松。
    • 在我看来,它与the accepted answer 非常相似。
    • 是的,您必须从用户那里获取一个字符串并将其存储在一个变量中,那部分是相同的。正如我的回答中所解释的,解析部分更简洁。
    • 解析部分更简洁 — 类似“使用Option::expect 而不是match 更简洁并在出现错误时失败”这样的注释会是等价的。 一个完整的答案让读者更容易 - 这个答案缺少必要的use std::iofn main,这是公认的答案以及真正的初学者想要的。
    • 为清楚起见,请随时留下答案,其他人可能会觉得它有用并点赞。只要有散文来描述为什么它不同且更好,它就是一个有效的答案!
    【解决方案4】:

    如果您正在寻找一种方法来读取输入以在您无权访问 text_io 的网站(例如 codeforces)上进行竞争性编程,那么此解决方案适合您。

    我使用以下宏从stdin 中读取不同的值:

    
    #[allow(unused_macros)]
    macro_rules! read {
        ($out:ident as $type:ty) => {
            let mut inner = String::new();
            std::io::stdin().read_line(&mut inner).expect("A String");
            let $out = inner.trim().parse::<$type>().expect("Parsable");
        };
    }
    
    #[allow(unused_macros)]
    macro_rules! read_str {
        ($out:ident) => {
            let mut inner = String::new();
            std::io::stdin().read_line(&mut inner).expect("A String");
            let $out = inner.trim();
        };
    }
    
    #[allow(unused_macros)]
    macro_rules! read_vec {
        ($out:ident as $type:ty) => {
            let mut inner = String::new();
            std::io::stdin().read_line(&mut inner).unwrap();
            let $out = inner
                .trim()
                .split_whitespace()
                .map(|s| s.parse::<$type>().unwrap())
                .collect::<Vec<$type>>();
        };
    }
      
    

    如下使用:

    
    fn main(){
       read!(x as u32);
       read!(y as f64);
       read!(z as char);
       println!("{} {} {}", x, y, z);
    
       read_vec!(v as u32); // Reads space separated integers and stops when newline is encountered.
       println!("{:?}", v);
    }
    
    

    【讨论】:

      【解决方案5】:

      parse 差不多;这是read_line,现在很不愉快。

      use std::io;
      
      fn main() {
          let mut s = String::new();
          io::stdin().read_line(&mut s).unwrap();
      
          match s.trim_right().parse::<i32>() {
              Ok(i) => println!("{} + 5 = {}", i, i + 5),
              Err(_) => println!("Invalid number."),
          }
      }
      

      【讨论】:

        【解决方案6】:

        如果你想要一个简单的语法,你可以创建一个扩展方法:

        use std::error::Error;
        use std::io;
        use std::str::FromStr;
        
        trait Input {
            fn my_read<T>(&mut self) -> io::Result<T>
            where
                T: FromStr,
                T::Err: Error + Send + Sync + 'static;
        }
        
        impl<R> Input for R where R: io::Read {
            fn my_read<T>(&mut self) -> io::Result<T>
            where
                T: FromStr,
                T::Err: Error + Send + Sync + 'static,
            {
                let mut buff = String::new();
                self.read_to_string(&mut buff)?;
        
                buff.trim()
                    .parse()
                    .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))
            }
        }
        
        // Usage:
        
        fn main() -> io::Result<()> {
            let input: i32 = io::stdin().my_read()?;
        
            println!("{}", input);
        
            Ok(())
        }
        

        【讨论】:

          【解决方案7】:

          你可以试试这段代码

          fn main() {
          
              let mut line  = String::new();
          
              // read input line string and store it into line
              std::io::stdin().read_line(&mut line).unwrap();
          
              // convert line to integer
              let number : i32 = line.trim().parse().unwrap();
          
              println!("Your number {}",number);
          }
          

          现在你可以编写一个函数来获取用户输入并像下面这样每次都使用它

          fn main() {
          
              let first_number = get_input();
              let second_number = get_input();
          
              println!("Summation : {}",first_number+second_number);
          
          }
          
          fn get_input() -> i32{
          
              let mut line  = String::new();
              std::io::stdin().read_line(&mut line).unwrap();
              let number : i32 = line.trim().parse().unwrap();
              return number ;
          }
          

          【讨论】:

            【解决方案8】:

            我肯定会使用 Rust-Lang 提供的文件系统 std::fs(在此处查看更多信息:https://doc.rust-lang.org/stable/std/fs/)但更特别的是 https://doc.rust-lang.org/stable/std/fs/fn.read_to_string.html

            假设你只想读取文本文件的输入,试试这个:

            use std::fs
            or
            use std::fs::read_to_string
            
            fn main() {
                println!("{}", fs::read_to_string("input.txt"));   
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2014-08-18
              • 2013-06-23
              • 2017-10-07
              • 1970-01-01
              • 1970-01-01
              • 2014-02-14
              相关资源
              最近更新 更多