【翻译】Rust中函数的参数默认值

问题:

Default function arguments in Rust

Rust中函数的参数默认值


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

在Rust中创建一个带默认参数的函数可能么?

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

评论:

#6973 contains several work-arounds (using a struct).

#6973 包含了一些变通方法(使用一个结构体)。


In 2020, how do you can code it?

在2020年,你怎么样能够编写这样的代码?


@puentesdias The accepted answer is still the correct answer. There is no way to do it in Rust, and you have to either write a macro, or use Option and explicitly pass None. 

@puentesdias 接受的的回答仍然是正确的答案。在Rust中没有办法这样做,你要么写一个宏,要么使用Option并显式的传递None。


回答1(accepted)(up 55):

No, it is not at present. I think it likely that it will eventually be implemented, but there’s no active work in this space at present.

不,现在它是不能的。我认为最终可能会实现它,但是现在在这个领域内是不能工作的。


The typical technique employed here is to use functions or methods with different names and signatures.

这里使用的是经典技术,使用函数或者方法时带不同的名字和函数定义。


评论:

@ner0x652: but note that that approach is officially discouraged. 

@ner0x652:但是注意这种做法官方是不鼓励的。


@ChrisMorgan Do you have a source for that being officially discouraged? 

@ChrisMorgan 对于官方不鼓励这个说法你有出处么?


@JeroenBollen The best I can come up with in a couple of minutes’ searching is reddit.com/r/rust/comments/556c0g/…, where you have people like brson who was the Rust project leader at the time. IRC might have had more, not sure.

@JeroenBollen 我能在几分钟内查询到的最好的是reddit.com/r/rust/comments/556c0g/…,这里有像brson这样的人,他是当时Rust项目的负责人,IRC可能会有更多,不确定。


回答2(up 109):

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

因为默认参数是不支持的,你可以使用Option得到相似的行为。

fn add(a: Option, b: Option) -> 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.

这个完成了对象有默认值,并且函数仅仅编码一次(代替每一次调用),当然很多东西要打印出来。函数调用将看起来像add(None, None),你喜欢还是不喜欢取决于你的观点。


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

如果你看见在参数列表打印不出任何东西,那是因为编码者可能是忘记做一个选择,那么这里一个大的优势是显而易见的;调用者需要明确的说他们带着你的默认值运行,如果他们什么都没有输入就会得到一个编译错误。把它想象成打印add(DefaultValue, DefaultValue)。


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

两种解决方案有非常大的不同,带“Option”参数方法写成add(None, Some(4))是完全有效的,但是宏匹配方法你是不能的(这个和Python的默认参数规则相似)。


You could also use an "arguments" struct and the From/Into traits:

你也可以使用一个“参数”结构体和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 for FooArgs {

    fn from(a: f64) -> Self {

        Self {

            a: a,

            ..Self::default()

        }

    }

}

impl From 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(arg_like: A) -> f64

where

    A: Into,

{

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

}

This choice is obviously a lot more code, but unlike the macro design it uses the type system which means the compiler errors will be more helpful to your library/API user. This also allows users to make their own From implementation if that is helpful to them.

这个选择很明显需要更多的代码,但是不像宏设计,它使用系统打印,意味着编译器报错将会对你的库/API使用者有更多帮助的。这也允许使用者做他们自己的From实现,如果对它们有用的话。


评论:

this answer would be better as several answers, one for each approach. i want to upvote just one of them

这个回答最好有好几个答案,每一个方法对应一个。我只支持它们中的一个。


回答3(up 57):

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

不能,Rust不支持函数默认参数。你不得不使用不同的名字来定义不同的方法。也没有方法重载,因为Rust使用函数名字来派生类型(函数重载要求正好相反)


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]

应要求,我从一个重复的问题中把这个回答跨帖贴上来。


评论:

This is a very useable pattern for default arguments. Should be higher up

这个对于默认参数是非常有用的模式。应该获得更高的支持。


你可能感兴趣的:(【翻译】Rust中函数的参数默认值)