2017-01-10 2 views
1

私が持っている機能:結果の戻り値でfoldを使用するにはどうすればよいですか?

fn test<T: FromStr>(text: &str) -> Result<T, SaleError> 

SaleErrorは、この場合の私のカスタムのエラー構造体です。

私は同じ位置の値を乗算し、その結果を合計する2つの配列があります。関数は配列と試行がmult_and_sum機能にfoldを呼び出すよりも、両方を圧縮しようとする

fn calculate_result() -> Result<f64, SaleError> { 
    let q_coms = ["1", "2", "3"]; 
    let v_un_coms = ["1", "2", "3"]; 
    Ok(try!(q_coms.iter().zip(v_un_coms.iter()).fold(0.0, mult_and_sum))) 
} 

を:

fn mult_and_sum(sum: f64, (q_com, v_un_com): (&str, &str)) -> Result<f64, SaleError> { 
    Ok(sum + try!(test::<f64>(q_com)) * try!(test::<f64>(v_un_com))) 
} 

問題は、私の知る限り理解できるよう、foldが署名

で関数を期待していることです

失敗する可能test機能は、どのように私はそれが失敗したので、もしResult戻り値でfoldを使用することができますので、calculate_resultErr(SaleError)を返すのだろうか?

+2

、私はhttps://github.com/rust-lang/rust/([ 'Result'に直接そのサポートを追加するためにPR]持っていますプル/ 38580)。 – Shepmaster

答えて

5

推測する必要はありません。エラーメッセージが表示されます。私はそれがより明確にするために、それを再編成しました:

actual: for<'r, 'r> std::ops::FnMut<(f64, (&'r str, &'r str))> 
required:    std::ops::FnMut<({float}, (&&str, &&str))> 

また(expected &str, found str)を言います。これは、スライスのスライス(&[&str])があるためです。スライスのイテレータは各要素への参照を返しますので、値は&&strです。この関数は&strを受け入れますが、それは不一致です。フリップ側

documentation for foldは、それが期待するものを示しています。すなわち

fn fold<B, F>(self, init: B, f: F) -> B 
    where F: FnMut(B, Self::Item) -> B 

foldは、いくつかのタイプ(init: B)の初期値、および機能(f: F、値(self)反復子を取り)。この関数はイテレータの値を受け取り、型(FnMut(B, Self::Item) -> B)を返します。

Resultを返したいので、Bをそれに固定する必要があります。つまり、アキュムレータがResultである必要があります。おそらくOkが必要です。そうしないと、最初から失敗します。 and_then

pairs.fold(Ok(0.0), |acc, (a, b)| 
    acc.and_then(|old| mult_and_sum(old, (a, b))) 
) 

そしてを簡略化することができ

fn calculate_result() -> Result<f64, SaleError> { 
    let q_coms = ["1", "2", "3"]; 
    let v_un_coms = ["1", "2", "3"]; 
    let pairs = q_coms.iter().zip(v_un_coms.iter()); 
    pairs.fold(Ok(0.0), |acc, (a, b)| { 
     match acc { 
      Ok(old) => mult_and_sum(old, (a, b)), 
      other => other, 
     } 
    }) 
} 

多分ビットのように小さい::私たちはclonedを使用

let pairs = q_coms.iter().cloned().zip(v_un_coms.iter().cloned()); 
pairs.fold(Ok(0.0), |acc, i| acc.and_then(|old| mult_and_sum(old, i))) 

変換するのは、その直接の実装をやってみましょう&&strから&strに変更することもできますが、機能を受け入れ可能に変更することもできますa &&str

2

test関数が失敗する可能性がありますので、それが失敗したので、もし[1つの要素がErrの場合]どのように私は、Result戻り値を倍に使用することができますか?

アキュムレータ(各繰り返しで「変更」されたもの)は、Resultである必要があります。このコードを見てください:

let q_coms = ["1", "2", "3"]; 
let v_un_coms = ["1", "2", "3"]; 

q_coms.iter() 
    // We don't need to call `iter()` on `v_un_coms`, because `zip()` 
    // takes an argument which implements `IntoIterator` 
    .zip(&v_un_coms) 

    // As you can see: the starting value is `Ok(0.0)` to say: so far, 
    // there was no error. 
    .fold(Ok(0.0), |acc, (a, b)| { 
     // The `and_then()` method calls the given closure when the `acc` 
     // (the outer one) is `Ok`. The inner `acc` represents the `Ok` 
     // value. The closure will then return another `Result`. 
     acc.and_then(|acc| { 
      // More fun with `and_then()` and `map()`. Read docs for more 
      // information. 
      test::<f64>(a) 
       .and_then(|a| test::<f64>(b).map(|b| a * b)) 
       .map(|new_product| acc + new_product) 
     }) 
    }) 

Try it on playground)面白いこと

関連する問題