2016-06-01 5 views
5

fand ich this discussion über Tupel splatting, aber es ist von 2014Tuple Splat/apply in Rust

Das Beispiel ist:

fn sum(x: i32, y: i32) -> i32 { 
    x + y 
} 

fn prepare_args() -> (i32, i32) { 
    (1, 2) 
} 

fn main() { 
    sum(prepare_args()); // Doesn't work 
} 

Und die vorgeschlagene Lösung ist Ihre eigene apply Funktion zu rollen:

fn apply<A,B,C>(f: |A,B|->C, t: (A,B)) -> C { 
    let (a,b) = t; 
    f(a,b) 
} 

fn main() { 
    apply(sum, prepare_args()); 
} 

Ist dies derzeit der beste Weg zu gehen? Wenn ja, wie lautet die korrekte Syntax? Ich bekomme einige Fehler einschließlich expected type, found | at line 1 col 20 mit dem oben genannten.

Gibt es noch keinen Tupel Splat Operator?

Antwort

6

Ich glaube nicht, dass es einen Splat-Operator gibt.

Der Code, den Sie 2014 gefunden haben, stammt aus der Zeit vor Rust 1.0, also ist er veraltet. Um die apply Funktion Arbeit in der Post 1.0 Rust zu machen, ändern Sie ihn in die folgenden:

fn sum(x: i32, y: i32) -> i32 { 
    x + y 
} 

fn prepare_args() -> (i32, i32) { 
    (1, 2) 
} 

fn apply<A, B, C, F>(f: F, t: (A, B)) -> C 
    where F : Fn(A, B) -> C 
{ 
    let (a, b) = t; 
    f(a, b) 
} 

fn main() { 
    let x = apply(sum, prepare_args()); 
    println!("{}", x); 
} 

Dieser Code kompiliert und läuft korrekt auf the Rust playground.

Sie alternativ f(t.0, t.1) als Leib apply oder denaturiert, direkt in der Parameterliste (Playground) verwenden:

fn apply<A, B, C, F>(f: F, (a, b): (A, B)) -> C 
    where F : Fn(A, B) -> C 
{ 
    f(a, b) 
} 
5

eine negative Proving ist immer recht schwierig ...

Soweit ich weiß, gibt es in der Tat kein Tupel Splat-Operator. Die Fn* Familie von Merkmalen (Fn) nimmt jedoch ein einzelnes Argument als Tupel.

Auf einem nächtlichen Compiler, einige instabilen Funktionen aktivieren, können Sie so verwenden:

#![feature(fn_traits)] 
#![feature(unboxed_closures)] 

fn sum(x: i32, y: i32) -> i32 { 
    x + y 
} 

fn prepare_args() -> (i32, i32) { 
    (1, 2) 
} 

fn main() { 
    let func: &Fn(i32, i32) -> i32 = &sum; 
    let result = func.call(prepare_args()); 
    println!("{:?}", result); 
} 

Nicht zu ideal, aber dann in Abwesenheit von Unterstützung für variadics, müssen Sie immer die Anzahl der Elemente wissen Ihr Tupel sowieso, also ist der Wert niedrig.

3

Hier ist eine Version von apply, die für Tupel mit Größen von 1 bis 6 arbeitet (kann vergrößert werden) (Playground):

fn main() { 
    let add1 = |x| x + 1; 
    let sum2 = ::std::ops::Add::add; 
    let sum3 = |a, b, c| a + b + c; 
    assert_eq!(apply(add1, (1,)), 2); 
    assert_eq!(apply(sum2, (1, 2)), 3); 
    assert_eq!(apply(sum3, (1, 2, 3)), 6); 
} 

#[inline(always)] 
pub fn apply<Fun, In, Out>(fun: Fun, params: In) -> Out 
    where ApplyImpl: Apply<Fun, In, Out> 
{ 
    ApplyImpl::apply(fun, params) 
} 

pub trait Apply<Fun, In, Out> { 
    fn apply(fun: Fun, params: In) -> Out; 
} 

pub struct ApplyImpl; 

macro_rules! impl_apply { 
    () =>(); 
    ($A:ident, $($B:ident,)*) => (
     impl_apply!{$($B,)*} 

     impl<$A, $($B,)* Fun, Out> Apply<Fun, ($A, $($B),*), Out> for ApplyImpl 
     where Fun: Fn($A, $($B),*) -> Out 
     { 
      #[allow(non_snake_case)] 
      #[inline(always)] 
      fn apply(fun: Fun, params: ($A, $($B),*)) -> Out { 
       // use type parameters as var names... 
       let ($A, $($B),*) = params; 
       fun($A, $($B),*) 
      } 
     } 
    ) 
} 

impl_apply!{A, B, C, D, E, F,} 

ich denke, in eine Kiste erstellen dafür. Wenn ich das tue, werde ich den Link hier setzen.