在Rust中是否可以使用默认参数创建函数?
fn add(a: int = 1, b: int = 2) { a + b }
在Rust中是否可以使用默认参数创建函数?
fn add(a: int = 1, b: int = 2) { a + b }
Option
并显式传递None
。
Answers:
由于不支持默认参数,因此您可以使用以下类似行为 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的默认参数规则类似)。
您还可以使用“参数”结构和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 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);
}
另一种方法是声明一个带有可选params作为变体的枚举,可以将其参数化为每个选项采用正确的类型。该函数可以实现为获取可变长度的枚举变量。它们可以是任意顺序和长度。默认值在功能内作为初始分配实现。
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