Подтвердить что ты не робот

Параметры функции по умолчанию в Rust

Возможно ли в Rust создать функцию с аргументом по умолчанию?

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

Ответ 1

Нет, это не в настоящее время. Я думаю, что это, вероятно, будет осуществлено, но в настоящее время нет активной работы в этом направлении.

Типичный метод, используемый здесь, заключается в использовании функций или методов с разными именами и сигнатурами.

Ответ 2

Поскольку аргументы по умолчанию не поддерживаются, вы можете получить аналогичное поведение, используя Option<T>

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

Это решает задачу иметь значение по умолчанию и функцию, закодированную только один раз (вместо каждого вызова), но, конечно, намного больше, чтобы напечатать. Вызов функции будет выглядеть как add(None, None), что может вам нравиться или не нравиться в зависимости от вашей перспективы.

Если вы видите, что ничего не печатаете в списке аргументов, поскольку кодировщик потенциально забывает сделать выбор, тогда большое преимущество здесь заключается в явности; вызывающая сторона явно говорит, что они хотят использовать ваше значение по умолчанию, и получит ошибку компиляции, если они ничего не установят. Думайте об этом как о вводе add(DefaultValue, DefaultValue).

Вы также можете использовать макрос:

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

Большая разница между этими двумя решениями заключается в том, что с аргументами "Option" -al вполне допустимо написать add(None, Some(4)), но с сопоставлением с шаблоном макроса нельзя (это похоже на правила аргументов Python по умолчанию)).

Вы также можете использовать структуру "arguments" и черты From/Into:

pub struct FooArgs {
    a: f64,
    b: i32,
}

impl Default for FooArgs {
    fn default() -> Self {
        FooArgs { a: 1.0, b: 1 }
    }
}

impl From<()> for FooArgs {
    fn from(_: ()) -> Self {
        Self::default()
    }
}

impl From<f64> for FooArgs {
    fn from(a: f64) -> Self {
        Self {
            a: a,
            ..Self::default()
        }
    }
}

impl From<i32> for FooArgs {
    fn from(b: i32) -> Self {
        Self {
            b: b,
            ..Self::default()
        }
    }
}

impl From<(f64, i32)> for FooArgs {
    fn from((a, b): (f64, i32)) -> Self {
        Self { a: a, b: b }
    }
}

pub fn foo<A>(arg_like: A) -> f64
where
    A: Into<FooArgs>,
{
    let args = arg_like.into();
    args.a * (args.b as f64)
}

fn main() {
    println!("{}", foo(()));
    println!("{}", foo(5.0));
    println!("{}", foo(-3));
    println!("{}", foo((2.0, 6)));
}

Этот выбор, очевидно, намного больше кода, но в отличие от макроса, он использует систему типов, что означает, что ошибки компилятора будут более полезны для вашей библиотеки/пользователя API. Это также позволяет пользователям самостоятельно создавать реализацию From если это им полезно.

Ответ 3

Нет, Rust не поддерживает аргументы функции по умолчанию. Вы должны определить разные методы с разными именами. Также нет функции перегрузки, потому что имена функций использования Rust для получения типов (функция перегрузки требует противоположного).

В случае инициализации структуры вы можете использовать синтаксис обновления структуры следующим образом:

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

[по запросу я перекрестил этот ответ по дублированному вопросу]

Ответ 4

Если вы используете Rust 1.12 или новее, вы можете, по крайней мере, упростить использование аргументов функции с помощью Option и 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);
}

Ответ 5

Rust не поддерживает аргументы функций по умолчанию, и я не верю, что это будет реализовано в будущем. Поэтому я написал proc_macro duang, чтобы реализовать его в виде макроса.

Например:

duang! ( fn add(a: i32 = 1, b: i32 = 2) -> i32 { a + b } );
fn main() {
    assert_eq!(add!(b=3, a=4), 7);
    assert_eq!(add!(6), 8);
    assert_eq!(add(4,5), 9);
}