2015-11-18 16 views
9

Kann ich im folgenden Beispielprogramm vermeiden, map2 definieren zu müssen?Gibt es eine Möglichkeit, zwei Optionen zu "kombinieren"?

fn map2<T, U, V, F: Fn(T, U) -> V>(f: F, a: Option<T>, b: Option<U>) -> Option<V> { 
    match a { 
     Some(x) => match b { 
      Some(y) => Some(f(x, y)), 
      None => None, 
     }, 
     None => None, 
    } 
} 

fn main() { 
    let a = Some(5); 
    let b = Some(10); 
    let f = |a, b| { 
     a + b 
    }; 
    let res = map2(f, a, b); 
    println!("{:?}", res); 
    // prints Some(15) 
} 

Für Menschen, die auch Haskell sprechen, ich denke, diese Frage auch formuliert werden könnte, „Gibt es ein Werkzeug, das wir statt liftM2 in Rust verwenden kann?“

Antwort

12

Ich glaube nicht, dass es eine direkte Funktion entspricht liftM2, aber Sie können Option::and_then und Option::map wie folgt kombiniert werden:

fn main() { 
    let a = Some(5); 
    let b = Some(10); 
    let f = |a, b| { 
     a + b 
    }; 

    println!("{:?}", a.and_then(|a| b.map(|b| f(a, b)))); 
} 

Ausgang:

Some(15) 
+0

Danke, das ist eigentlich eine ziemlich gute Lösung, wenn Sie nur brauchen um dies ein- oder zweimal zu machen. Wahrscheinlich lohnt es sich aber trotzdem, die Funktion in einigen Fällen zu definieren. –

4

Sie die Tatsache, dass Option verwenden können s kann iteriert werden. Iterieren Sie beide Optionen, zippen Sie sie zusammen und ordnen Sie den resultierenden Iterator der Funktion zu.

fn main() { 
    let a = Some(5); 
    let b = Some(10); 
    let f = |(a, b)| { 
     a + b 
    }; 
    let res = a.iter().zip(b.iter()).map(f).next(); 
    println!("{:?}", res); 
    // prints Some(15) 
} 

Dies erforderte eine Modifikation von f, so werden die Argumente in einem einzigen Tupel-Argument verschmolzen. Es wäre ohne Änderung f möglich, direkt über |args| f.call(args) zu mappen, aber dann müssten Sie specify the closure kind of f.

+0

Alternative: 'map (| (a, b) | f (a, b))' – sellibitze

+0

ja, ich versuchte zu vermeiden, den Funktionsaufruf zu wiederholen. Wenn Sie es wiederholen, ist @ Dogberts Lösung die bessere Lösung. –

2

Ich weiß nicht, ob Sie nach unten, um eine Zeile zu bekommen, aber Sie können die verschachtelten match durch Abgleich auf einem Tupel vermeiden:

let a = Some(5); 
let b = Some(10); 
let f = |a, b| { 
    a + b 
}; 
let res = match (a, b) { 
    (Some(a), Some(b)) => Some(f(a, b)), 
    _ => None, 
}; 
println!("{:?}", res); 
// prints Some(15) 
Verwandte Themen