6

这是我的第一个 Rust 程序,似乎我已经遇到了可怕的借用检查器。:)

程序应该读取命令行中传递的参数,对它们求和并返回结果。我无法将参数解析为整数。

use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();
    let sum_args: i32 =
        args
        .iter()
        .skip(1)
        .fold(0, |a, &b| a + b.parse::<i32>().ok().expect("Not an i32!"));
    println!("{:?}", sum_args.to_string());
}

失败了:

error[E0507]: cannot move out of borrowed content
 --> src/main.rs:9:22
  |
9 |         .fold(0, |a, &b| a + b.parse::<i32>().ok().expect("Not an i32!"));
  |                      ^-
  |                      ||
  |                      |hint: to prevent move, use `ref b` or `ref mut b`
  |                      cannot move out of borrowed content

我应该如何进行?

4

1 回答 1

9

args是 a Vec<String>,并且iter迭代器返回对字符串 ( &String) 的引用。查看类型的一个技巧是尝试为单元类型分配一个值()

let () = args.iter().next();

其中有一个显示类型的错误:

error[E0308]: mismatched types
 --> src/main.rs:5:13
  |
5 |         let () = args.iter().next();
  |             ^^ expected enum `std::option::Option`, found ()
  |
  = note: expected type `std::option::Option<&std::string::String>`
  = note:    found type `()`

在您的闭包中,您试图自动取消引用 ( |a, &b|) 第二个值。如果您能够取消引用它,那么String将被移出向量,这将使向量中的内存处于不确定状态!如果我们在此之后尝试使用向量,我们可能会导致段错误,这是 Rust 旨在帮助防止的事情之一。

最简单的事情是根本不取消引用它(保留b为 a &String):

use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();
    let sum_args: i32 =
        args
        .iter()
        .skip(1)
        .fold(0, |a, b| a + b.parse::<i32>().expect("Not an i32!"));
    println!("{:?}", sum_args.to_string());
}

一些额外的小点...

当您执行以下操作时,您不必指定向量元素类型collect

let args: Vec<_> = env::args().collect();

您无需创建字符串即可打印出数字:

println!("{}", sum_args);

我可能会把它写成

use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();
    let sum_args: i32 =
        args
        .iter()
        .skip(1)
        .map(|n| n.parse::<i32>().expect("Not an i32!"))
        .sum();
    println!("{}", sum_args);
}

过于聪明的解决方案警告

如果你必须总结一堆可能失败的数字的迭代器,你可以创建一个实现FromIterator但不分配任何内存的类型:

use std::env;
use std::iter::{FromIterator, Sum};

struct SumCollector<T>(T);

impl<T> FromIterator<T> for SumCollector<T>
    where T: Sum
{
    fn from_iter<I>(iter: I) -> Self
        where I: IntoIterator<Item = T>
    {
        SumCollector(iter.into_iter().sum())
    }
}

fn main() {
    let sum: Result<SumCollector<i32>, _> = env::args().skip(1).map(|v| v.parse()).collect();
    let sum = sum.expect("Something was not an i32!");
    println!("{}", sum.0);
}

Rust 1.16 甚至应该支持这个开箱即用:

use std::env;

fn main() {
    let sum: Result<_, _> = env::args().skip(1).map(|v| v.parse::<i32>()).sum();
    let sum: i32 = sum.expect("Something was not an i32!");
    println!("{}", sum);
}
于 2015-04-09T13:20:31.357 回答