web-dev-qa-db-ja.com

Rustのデフォルトの関数引数

Rustでデフォルト引数で関数を作成することは可能ですか?

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

いいえ、現時点ではありません。最終的には実装される可能性が高いと思いますが、現在この分野では積極的な作業はありません。

ここで使用される典型的な手法は、異なる名前とシグネチャを持つ関数またはメソッドを使用することです。

35
Chris Morgan

デフォルトの引数はサポートされていないため、_Option<T>_を使用して同様の動作を得ることができます

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

これにより、デフォルト値と関数を(呼び出しごとにではなく)1回だけコーディングするという目的が達成されますが、もちろん、入力するのははるかに多くなります。関数呼び出しは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);
_

2つのソリューションの大きな違いは、「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実装が役立つ場合もあります。

48
ampron

いいえ、Rustはデフォルトの関数引数をサポートしていません。異なるメソッドを異なる名前で定義する必要があります。Rust use function型を導出するための名前(関数のオーバーロードには逆が必要です)。

構造体の初期化の場合、次のような構造体更新構文を使用できます。

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

[リクエストに応じて、重複した質問からこの回答をクロスポストしました]

29
eulerdisk

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

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);
}
1
zhengmian hu