103

How can I create a function with a variable number of arguments in Rust?

Like this Java code:

void foo(String... args) {
    for (String arg : args) {
        System.out.println(arg);
    }
}

3 Answers 3

116

In general, you can't - Rust does not support variadic functions, except when interoperating with C code that uses varargs.

In this case, since all of your arguments are the same type, you can accept a slice:

fn foo(args: &[&str]) {
    for arg in args {
        println!("{}", arg);
    }
}

fn main() {
    foo(&["hello", "world", "I", "am", "arguments"]);
}

(Playground)

Beyond that, you can explicitly accept optional arguments:

fn foo(name: &str, age: Option<u8>) {
    match age {
        Some(age) => println!("{} is {}.", name, age),
        None      => println!("Who knows how old {} is?", name),
    }
}

fn main() {
    foo("Sally", Some(27));
    foo("Bill", None);
}

(Playground)

If you need to accept many arguments, optional or not, you can implement a builder:

struct Arguments<'a> {
    name: &'a str,
    age: Option<u8>,
}

impl<'a> Arguments<'a> {
    fn new(name: &'a str) -> Arguments<'a> {
        Arguments {
            name: name,
            age: None
        }
    }

    fn age(self, age: u8) -> Self {
        Arguments {
            age: Some(age),
            ..self
        }
    }
}

fn foo(arg: Arguments) {
    match arg.age {
        Some(age) => println!("{} is {}.", arg.name, age),
        None      => println!("Who knows how old {} is?", arg.name),
    }
}

fn main() {
    foo(Arguments::new("Sally").age(27));
    foo(Arguments::new("Bill"));
}

(Playground)

Sign up to request clarification or add additional context in comments.

Comments

39

In the general case where your types may differ, you can use a macro:

macro_rules! print_all {
    ($($args:expr),*) => {{
        $(
            println!("{}", $args);
        )*
    }}
}

fn main() {
    print_all!(1, 2, "Hello");
}

Playground

As another example, if you want to fold over the arguments, you can do something like this:

macro_rules! sum {
    ($($args:expr),*) => {{
        let result = 0;
        $(
            let result = result + $args;
        )*
        result
    }}
}

fn main() {
    assert_eq!(sum!(1, 2, 3), 6);
}

Playground

See the Rust book's simplified implementation of vec![...] for another example.

Comments

10
fn variable_func<T>(_vargs: &[T]) {}

fn main() {
    variable_func(&[1]);
    variable_func(&[1, 2]);
    variable_func(&["A", "B", "C"]);
}

5 Comments

@Shepmaster Compiles now. Yes, i agree on the allocation part. Is there a similar way without allocation ?
ah yes, the macro is really not needed here. I will modify the answer according to your comment.
what if i want the function take the ownership of the array?
@qiuxiafei unless you can hard-code the size of the array (thus making it not variadic), or you write a variant for every [T; N] you want to support, you'll have to give it a Vec<T>
@kbolino yes, i thinks Vec<T> is the only solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.