2016-01-15 11 views
9

Rustは一般的な戻り値の型でクロージャをサポートしますか?たとえば、次のような記述をしたいとします。ジェネリッククロージャを定義することはできますか?

let get<T: FromValue> = |s: &str| -> Option<T> { ... } 

しかし、この構文は明らかに間違っています。私はrust-mysql-simpleで働いている

やろうとしている、と私はデータベース行からユーザーを構築するために、私のUser構造体のためfrom_row方法を書いて何

ライブラリは、(私が知る限り)クエリ結果の行の値を列名で検索する方法を提供していません。だから、この問題を回避するために、私の方法は、(これはコンパイルし、正常に動作する)ようになっています

ここ
fn from_row(result: &QueryResult, row: Vec<Value>) -> User { 

    let mut map: HashMap<_, _> = row.into_iter().enumerate().collect(); 

    let mut get = |s: &str| { 
     result.column_index(s) 
      .and_then(|i| map.remove(&i)) 
    }; 

    User { 
     id: get("id").and_then(|x| from_value_opt(x).ok()) 
    } 
} 

resultが(列名の列インデックスを見つけるために使用されるクエリの列名についての情報を含むオブジェクトであります)、rowには、クエリ結果の行から順序付けられた値が含まれています。 from_value_optは、ライブラリによって提供されるメソッドで、Valueを返し、Result<T, MyError>を返します。値はフィールドの型に変換されます。

私は.and_then(|x| from_value_opt(x).ok())getクロージャに移動しようとしていましたが、コードの一部をクリーンアップしました。しかし、私がそうすると、クロージャの戻り値の型はget呼び出しの最初の発生の結果であると解釈されます。

私は次のようになり、ネストされた方法として閉鎖を書き直し:

もうまくいきましたが、はるかに冗長性をカットする助けにはならなかった
fn get<T: FromValue>(r: &QueryResult, m: &mut HashMap<usize, Value>, s: &str) 
    -> Option<T> { ... } 

+0

おかげで、私は私がやろうとしていますかについていくつかの情報を追加しました。 –

答えて

3

いいえ、AFAIKできません。つまり、と定義することはできません。一般的な左手側でletバインディングを作成することはできません。

fn get<T>は、あなたが書き換え言及1は、monomorphisationを受けるよう、すなわち、それをコンパイルするとき、rustcはそれを呼び出すために使用されているすべての実際のTためgetの異なるバージョンを生成します。その結果をgetlet a = get(...))に割り当てるときには、その結果は具体的なタイプとサイズになります。

letバインディングは単体化されないため、let a<T> = ...を持つことはできず、コンパイラによって異なるバージョンのaが生成されることはありません。

私がこれを可能にするかもしれないと思うのは、Rustの非常に望ましい新機能ではありませんが、より高度な種類の導入です。すなわち、私は後で(あなたが求めているものです)Tでパラメータ化することができますクロージャを返す

// does not work as of Rust 1 
let a = for<T> |s: &str, t: T| {...} 

:彼らのような何かを書くことができますでしょう。

+0

ありがとう!それは完璧な意味合いがあります。 –

+0

@kardeiz Userがどのように定義され、どのfrom_value_optが何を返すのか分からないが、実際には一般的になる必要はない可能性があり、from_value_opt :: (x) –

+0

はい、それはうまくいきますが、私の「User」フィールドには異なるタイプがあるので、それが私を助けるとは思わないでしょう。私はちょうど 'from_value_opt'呼び出しをクロージャーに置き、' get :: >( "id") 'のようにクロージャーを呼び出そうとしましたが、明らかに型パラメーターをクロージャーに渡すことはできません。 –

1

クロージャの種類は匿名ですので、書き留められないため、コンパイラが推論することができないようです。

しかし、閉鎖のを使用する特別な理由はありますか?私があなたの質問を正しく理解していれば、この機能を使っていくつかの反復アクションを除外し、実際にはそれを回すつもりはありません。したがって、内側のfnはうまく動作するはずです。欠点は、クロージャによって自動的にキャプチャされたすべての値を渡す必要があることです。

それはそのようなものになるだろう(例はまだかなり複雑ですので、私はそれをコンパイルしようとしませんでした):

fn from_row(result: &QueryResult, row: Vec<Value>) -> User { 
    let mut map: HashMap<_, _> = row.into_iter().enumerate().collect(); 

    fn get<T: FromValue>(s: &str, result: &QueryResult, map: &mut HashMap<_, _>) 
     -> T { 
     result.column_index(s) 
      .and_then(|i| map.remove(&i)) 
      .and_then(|x| from_value_opt(x)).ok() 
    }; 

    User { 
     id: get("id", &result, &mut map) 
    } 
} 
+0

答えをありがとう。はい、私は閉鎖を使用したかったのです - だから、私はそれらの値を渡す必要はありません。しかし、これが私のやり方です(私の質問の最後の部分を見てください)。 –

関連する問題