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でありVec<String>iter反復子は文字列 ( &String) への参照を返します。タイプを確認する 1 つのトリックは、ユニット タイプに値を割り当てようとすることです()

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|、2 番目の値を自動的に逆参照 () しようとしています。逆参照できた場合、ベクターStringから移動され、ベクター内のメモリが不確定な状態のままになります! この後にベクトルを使用しようとすると、セグメンテーション違反が発生する可能性があります。これは、Rust が防止するように設計されているものの 1 つです。

最も簡単なことは、それをまったく逆参照しないことです ( のままbにします&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 に答える