Возможно ли в Rust создать функцию с аргументом по умолчанию?
fn add(a: int = 1, b: int = 2) { a + b }
function
parameters
arguments
rust
Jeroen
источник
источник
Option
и явно передатьNone
.Ответы:
Нет, в настоящее время нет. Думаю, что в конечном итоге это будет реализовано, но в настоящее время активной работы в этом направлении нет.
Типичный метод, используемый здесь, заключается в использовании функций или методов с разными именами и сигнатурами.
источник
Поскольку аргументы по умолчанию не поддерживаются, вы можете получить аналогичное поведение, используя
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
реализации, если это им полезно.источник
Нет, 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); }
[по запросу я отправил этот ответ из дублированного вопроса]
источник
Rust не поддерживает аргументы функций по умолчанию, и я не верю, что это будет реализовано в будущем. Поэтому я написал дуанг proc_macro, чтобы реализовать его в форме макроса.
Например:
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); }
источник
Если вы используете 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); }
источник
Другой способ - объявить перечисление с необязательными параметрами как варианты, которые можно параметризовать, чтобы выбрать правильный тип для каждой опции. Функцию можно реализовать для получения фрагмента переменной длины из вариантов перечисления. Они могут быть любого порядка и длины. Значения по умолчанию реализованы в функции как начальные назначения.
enum FooOptions<'a> { Height(f64), Weight(f64), Name(&'a str), } use FooOptions::*; fn foo(args: &[FooOptions]) { let mut height = 1.8; let mut weight = 77.11; let mut name = "unspecified".to_string(); for opt in args { match opt { Height(h) => height = *h, Weight(w) => weight = *w, Name(n) => name = n.to_string(), } } println!(" name: {}\nweight: {} kg\nheight: {} m", name, weight, height); } fn main() { foo( &[ Weight(90.0), Name("Bob") ] ); }
выход:
name: Bob weight: 90 kg height: 1.8 m
источник