47

If I want to unpack a tuple and pass it as arguments is there a way to do this:

//Does not compile
fn main() {
    let tuple = (10, Vec::new());
    foo(tuple);
}
fn foo(a: i32, b: Vec<i32>) {
    //Does stuff.
}

Instead of having to do this:

fn main() {
    let tuple = (10, Vec::new());
    foo(tuple.0, tuple.1);
}
fn foo(a: i32, b: Vec<i32>) {
    //Does stuff.
}
Shepmaster
  • 326,504
  • 69
  • 892
  • 1,159
HiDefender
  • 1,738
  • 2
  • 9
  • 26

3 Answers3

24

On a nightly compiler:

#![feature(fn_traits)]

fn main() {
    let tuple = (10, Vec::new());
    std::ops::Fn::call(&foo, tuple);
}
fn foo(a: i32, b: Vec<i32>) {
}

There is AFAIK no stable way to do that.

mcarton
  • 24,420
  • 5
  • 70
  • 79
21

There is a way, using the magic of pattern matching:

fn main() {
    let tuple = (10, Vec::new());
    foo(tuple);
}

fn foo((a, b): (i32, Vec<i32>)) {
    // do stuff
}

As per Rust reference:

As with let bindings, function arguments are irrefutable patterns, so any pattern that is valid in a let binding is also valid as an argument.

So you can specify an argument like:

(a, b): (i32, Vec<i32>)

just like you would in a let statement.

ljedrz
  • 17,806
  • 3
  • 63
  • 86
  • 7
    can you elaborate about this a little bit more? Isn't it then like a calling a function with a single argument which happened to be a tuple? – piotao Jul 23 '20 at 22:28
  • 1
    @piotao Yes, `foo` is a one argument function that takes a tuple. It just so happens that the tuple is immediately pattern-matched and unpacked in the function parameters. – Colonel Thirty Two Jun 24 '21 at 16:26
10
let (a, b) = (10, Vec::new());
foo(a, b);
Lee
  • 138,123
  • 20
  • 222
  • 279
  • 13
    I upvoted, but this answer would be better if it explicitly answered the question rather than just offering alternative code. – trent Oct 05 '16 at 15:57