Default function arguments in Rust

2019-01-22 05:32发布

问题:

Is it possible in Rust to create a function with a default argument?

fn add(a: int = 1, b: int = 2) { a + b }

回答1:

No, it is not at present, and while I think it is likely that it will eventually be implemented, it's very unlikely to come before 1.0.

The typical technique employed here is different functions or methods with different signatures.



回答2:

Since default arguments are not supported you can get a similar behavior using Option<T>

fn add(a: Option<i32>, b: Option<i32>) -> i32 {
    a.unwrap_or(1) + b.unwrap_or(2)
}

This accomplishes the objective of having the default value and the function coded only once (instead of in every call), but is of course a whole lot more to type out. The function call will look like add(None, None), which you may or may not like depending on your perspective.

If you see typing nothing in the argument list as the coder potentially forgetting to make a choice then the big advantage here is in explicitness; the caller is explicitly saying they want to go with your default value, and will get a compile error if they put nothing. Think of it as typing add(DefaultValue, DefaultValue).

UPDATE:

You could also use a macro!

fn add(a: i32, b: i32) -> i32 { a + b }

macro_rules! add {
    ($a: expr) => { add($a, 2) };
    () => { add(1, 2) }
}

assert_eq!(add!(), 3);
assert_eq!(add!(4), 6);

The big difference between the two solutions is that with "Option"-al arguments it is completely valid to write add(None, Some(4)), but with the macro pattern matching you cannot (this is similar to Python's default argument rules).



回答3:

No, Rust doesn't support default function arguments. You have to define different methods with different names. There is no function overloading either, because Rust use function names to derive types (function overloading requires the opposite).

In case of struct initialization you can use the struct update syntax like this:

use std::default::Default;

#[derive(Debug)]
pub struct Sample {
    a: u32,
    b: u32,
    c: u32,
}

impl Default for Sample {
    fn default() -> Self {
        Sample { a: 2, b: 4, c: 6}
    }
}

fn main() {
    let s = Sample { c: 23, .. Sample::default() };
    println!("{:?}", s);
}

[on request, I cross-posted this answer from a duplicated question]



回答4:

If you are using Rust 1.12 or later, you can at least make function arguments easier to use with Option and into():

fn add<T: Into<Option<u32>>>(a: u32, b: T) -> u32 {
    if let Some(b) = b.into() {
        a + b
    } else {
        a
    }
}

fn main() {
    assert_eq!(add(3, 4), 7);
    assert_eq!(add(8, None), 8);
}