2016-06-01 7 views
5

ho trovato this discussion su tuple splatting, ma è a partire dal 2014.Tuple splat/applicare a Rust

L'esempio dato è:

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

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

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

E la soluzione proposta è quella di rotolare la propria funzione apply:

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()); 
} 

È attualmente il modo migliore per andare? In tal caso, qual è la sintassi corretta qui? Ottengo alcuni errori tra cui expected type, found | at line 1 col 20 utilizzando quanto sopra.

Non esiste ancora un operatore splat a tuple?

risposta

6

Non penso che ci sia un operatore di splat.

Il codice che hai trovato dal 2014 proviene da prima di Rust 1.0, quindi è obsoleto. Per far funzionare il apply funzione in fase di post 1.0 Rust, trasformarla in quanto segue:

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); 
} 

Questo codice compilato ed eseguito correttamente su the Rust playground.

Si potrebbe in alternativa utilizzare f(t.0, t.1) come il corpo di apply o destrutturare proprio lì nella lista dei parametri (Playground):

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

Dimostrando un negativo è sempre piuttosto difficile ...

Per quanto ne so, non c'è davvero nessun operatore tuple splat. Tuttavia, la famiglia di tratti Fn* (Fn) accetta un singolo argomento, come una tupla.

Su un compilatore di notte, l'attivazione di alcune caratteristiche instabili, è possibile quindi utilizzare:

#![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); 
} 

Non troppo ideale, ma poi, in assenza di supporto per variadics, è sempre necessario conoscere il numero di elementi di la tua tupla comunque il valore è basso.

3

Ecco una versione di apply che funziona per le tuple con dimensioni da 1 a 6 (può essere aumentato) (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,} 

sto pensando a creare una cassa per questo. Se lo faccio, inserirò il link qui.