web-dev-qa-db-ja.com

下線付きのプレフィックス付き変数が存在するのはなぜですか?

私はRustを学んでいて、変数名の先頭にアンダースコアを追加すると、コンパイラーが未使用の場合に警告を出さなくなるという事実に遭遇しました。未使用の変数が嫌われるので、なぜその機能が存在するのかと思います。

13
Sir Platypus

いくつかの理由がわかります。

  • #[must_use]型を返す関数を呼び出していますが、特定のケースでは、値を無視しても安全です。そのために_パターンを使用することは可能です(これは変数バインディングではなく、独自のパターンですが、これがおそらくアンダースコアプレフィックスの規則の元になる場所です)。値、またはその値が何であるかを無視します。これは、私の経験のテストで特に一般的です。
  • マクロ。マクロで作成された変数は、後で使用される場合と使用されない場合があります。マクロ呼び出しで警告を止めることができないのは不愉快です。この場合、アンダースコアを2倍にする規則があります。これは、たとえば、クリッピーの used_underscore_binding lintによって強制されます。
  • RAII。デストラクタの副作用のために変数を存在させたい場合がありますが、それ以外の場合は使用しないでください。 _は変数バインディングではなく、値はステートメントの最後で削除されるため、この使用例では単に_を使用することはできません。
11
mcarton

未使用の変数を無視する動作が必要な理由の例をいくつか示します。次の関数で__s_を検討してください。

_fn add_numbers(f: i32, _s: i32) -> i32 {
    f + 1
}
_

__s_変数を使用すると、実装していなくても署名を同じに保つことができます。これは、__s_が必要ないことがわかった場合にも機能しますが、ライブラリが非常に多くの異なるプロジェクトで使用されているため、APIを関数に変更したくありませんでした。これは悪い習慣かもしれませんし、そうでないかもしれませんが、__s_がとどまり、何もしない必要がある状況で役立ちます。ここで___を使用することもできますが、__s_は、将来の変数の目的に関してより多くの意味を持つ可能性があります。

これが役立つ次の場所は、型がDropを実装し、そのロジックがどこで発生するかを気にする場合です。この例では、Dropが最後に発生するように__result_変数が必要であることがわかります。

_fn main() {
    let mut num = 1;
    // let _ = try_add_numbers(&mut num); // Drop is called here for _
    let _result = try_add_numbers(&mut num); // without the _result we have a warning.

    println!("{}", num);
    // Drop is called here for the _result
}

// keep the api the same even if an aurgument isn't needed anymore or
// has not been used yet.
fn add_numbers(f: i32, _s: i32) -> i32 {
    f + 1
}

// This function returns a result
fn try_add_numbers(i: &mut i32) -> Result<GoodResult, GoodResult> {
    if *i > 3 {
        return Err(GoodResult(false));
    }
    *i = add_numbers(*i, 0);
    Ok(GoodResult(true))
}

struct GoodResult(bool);

impl Drop for GoodResult {
    fn drop(&mut self) {
        let &mut GoodResult(result) = self;
        if result {
            println!("It worked");
        } else {
            println!("It failed");
        }
    }
}
_

let _result = try_add_numbers(&mut num);を使用する場合、mainの最後までドロップされ、その後呼び出される変数が存在します。 let _ = try_add_numbers(&mut num);を使用した場合でも、警告は表示されませんが、ステートメントの最後でdropが呼び出されます。 letバインディングなしでtry_add_numbers(&mut num);を使用すると、警告が表示されます。このプログラムの出力は、try_add_numbers関数で使用する内容によって異なります。

_It worked
2
_

または

_2
It worked
_

したがって、___変数と__named_変数の両方を使用する必要があります。これらの変数は、プログラムの出力が何である必要があるかに基づいて選択する必要があります。 playground で私の例を試して、感じをつかんでください。

1
Daniel Wilkins

一致変数に関連するこの警告を調べている間、私はここでGoogleを見つけました。これは接線的に関連しています。

Resultを取得するコードがあり、大文字と小文字を区別したい場合がありますが、エラー値は気にしません。 _eなどを使用する代わりに、明示的にバインドしない_を実際に使用できます。具体的な例を示します。エラーを返すので、エラーの値は気にしません。

fn some_method() -> Result<u32, MyCustomError> {
    // ...
    let id: u32 = match some_str.parse() {
        Ok(value) => value,
        Err(_) => return Err(MyCustomError::Blah)
    }
    // ...
}
0
Captain Man