Rust中的默认函数参数

问题描述 投票:50回答:5

在Rust中是否可以使用默认参数创建函数?

fn add(a: int = 1, b: int = 2) { a + b }
function parameters arguments rust
5个回答
35
投票

不,目前不是。我认为最终可能会实施,但目前在这个领域还没有积极的工作。

这里采用的典型技术是使用具有不同名称和签名的函数或方法。


47
投票

由于不支持默认参数,因此您可以使用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,如果这对他们有帮助的话。


28
投票

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

[根据要求,我从一个重复的问题中交叉发布了这个答案]


3
投票

如果您使用Rust 1.12或更高版本,您至少可以使用Optioninto()更容易使用函数参数:

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

1
投票

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);
}
© www.soinside.com 2019 - 2024. All rights reserved.