Почему подчеркивание префиксных переменных существует?

Я изучаю Rust и столкнулся с тем фактом, что добавление подчеркивания в начале имени переменной заставит компилятор не предупреждать, если она не используется. Мне интересно, почему эта функция существует, так как неиспользуемые переменные осуждаются.

5 ответов

Решение

Я вижу несколько причин:

  • Вы вызываете функцию, которая возвращает #[must_use] типа, но в вашем конкретном случае вы знаете, что можете смело игнорировать значение. Можно использовать _ шаблон для этого (который не является привязкой к переменной, это собственный шаблон, но, вероятно, именно отсюда и происходит соглашение о префиксах подчеркивания), но вы можете задокументировать, почему вы игнорируете значение или что это за значение. Это особенно часто встречается в тестах по моему опыту.
  • Макросы. Переменная, созданная в макросе, может или не может использоваться позже. Было бы неприятно не иметь возможности отключить предупреждения при вызове макроса. В этом случае есть соглашение об удвоении символов подчеркивания, например, Clippy used_underscore_binding ворс.
  • RAII. Вы могли бы хотеть иметь переменную, существующую для ее побочного эффекта деструктора, но не использовать ее иначе. Не возможно просто использовать _ для этого варианта использования, как _ не является привязкой переменной, и значение будет отброшено в конце оператора.

Вот несколько примеров того, почему вы можете захотеть игнорировать неиспользуемую переменную. Рассматривать _s в следующей функции.

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

_s Переменная делает это таким образом, чтобы мы могли сохранить сигнатуру, даже если мы ее не реализовали. Это также работает, если мы узнали, что нам не нужно _s но поскольку наша библиотека используется во многих различных проектах, мы не хотели менять API для нашей функции. Это может или не может быть плохой практикой, но может быть полезно в ситуации, когда _s Нужно остаться и ничего не делать. Мы могли бы также использовать _ здесь, но _s потенциально имеет больше значения относительно того, для чего переменная в будущем.

Следующее место, где это может быть полезно, это когда тип реализует Drop и тебя волнует, где происходит эта логика. В этом примере вы можете увидеть, что _result переменная нужна, чтобы Drop бывает в конце.

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 и drop. Если бы мы использовали let _ = try_add_numbers(&mut num); мы все еще не получаем предупреждение, но в конце оператора вызывается drop. Если мы используем try_add_numbers(&mut num); без привязки let мы получаем предупреждение. Вывод этой программы меняется в зависимости от того, что мы используем с нашей функцией try_add_numbers.

It worked
2

или же

2
It worked

Таким образом, есть применение для обоих _ а также _named переменные, которые нужно выбирать в зависимости от того, какими должны быть выходные данные ваших программ. Поиграйте с моим примером на игровой площадке, чтобы почувствовать это.

  • является привязкой значения, и пространство стека будет выделено для хранения его значения.
  • let _aчто-то ведет себя как let a. Кроме того, он отмечен как intentional, чтобы компилятор не выдавал предупреждение, если _aне используется.
  • let _является шаблоном, и _это reserved identifierкоторые нельзя использовать в другом месте. Это не приведет к выделению пространства стека, поэтому значение в правой части =будет выпущен вскоре после этого заявления.

Вот пример: Детская площадка

      pub struct Node {
    value: usize,
}

impl Drop for Node {
    fn drop(&mut self) {
        println!("drop() {}", self.value);
    }
}

pub fn square() {
    let a = Node { value: 1 };
    let _a = Node { value: 2 };
    let _ = Node { value: 3 };

    println!("Hello, world!");
}

fn main() {
    square();
}

вывод:

      drop() 3
Hello, world!
drop() 2
drop() 1

Вы можете прочитать это , чтобы узнать больше

Я наткнулся здесь через Google, когда искал это предупреждение, связанное с переменными соответствия. Это косвенно связано.

Иногда у вас может быть код, в котором вы получаете Resultи хотите сопоставить случаи, но вас не волнует значение ошибки. Вместо того, чтобы использовать_e или что-то в этом роде, вы можете просто использовать _который явно не связывает. Вот конкретный пример. Нас не волнует значение ошибки, поскольку мы возвращаем свою собственную.

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

Просто определите тип переменной, т.е.

например:-

        fn names(){ //this case the function gives an warning like "help: if this is intentional, prefix it with an underscore: `_myname`"
      let myname = "yash";  
      }

поэтому с помощью последних изменений в вашем коде вы можете устранить эту ошибку: -

        fn name(){ //here warning won't come
     let myname: &str = "bash"
       }
 
Другие вопросы по тегам