Как вы используете параметр для функции, которая выдает ошибки в коде обработки ошибок?

#rust

#Ржавчина

Вопрос:

 fn test() {
    use std::path::PathBuf;
    use std::fs::File;

    let filename: PathBuf = PathBuf::from("hello");
    let filename_clone = filename.clone();
    match File::open(filename) {
        Ok(_fp) => {
            unimplemented!();
        }
        Err(_error) => {
            println!("{}", filename_clone.display()); // Works
            println!("{}", filename.display()); // Fails
        }
    }
}
  

Ошибка:

 error[E0382]: borrow of moved value: `filename`
  --> src/lib.rs:13:28
   |
5  |     let filename: PathBuf = PathBuf::from("hello");
   |         -------- move occurs because `filename` has type `std::path::PathBuf`, which does not implement the `Copy` trait
6  |     let filename_clone = filename.clone();
7  |     match File::open(filename) {
   |                      -------- value moved here
...
13 |             println!("{}", filename.display()); // Fails
   |                            ^^^^^^^^ value borrowed here after move
  

Игровая площадка

Мы понимаем, что использование filename завершается неудачно, потому File::open что оно заимствовано и еще не выпущено. Тем не менее, в случае open сбоя (скажем, из-за того, что файл не существует) мы хотим сообщить о фактических входных данных, предоставленных open . Мы можем обойти это, клонируя имя файла перед его открытием, но в этом случае мы по существу удваиваем объем памяти в ожидании, но не уверенности в возникновении ошибки. Это кажется неправильным.

Каков правильный способ справиться с этим случаем? Как вы выводите информацию из точки сбоя, что обеспечивает выразительную и точную обработку ошибок? Или я что-то недопонимаю в этом механизме, чтобы было понятно?

Комментарии:

1. @JohnKugelman разве это todo!() не маскирует ошибку ( play.rust-lang.org /… )?. (Также github.com/rust-lang/rust/issues/69834 ).

Ответ №1:

При вызове File::open(filename) filename он не был заимствован, а скорее перемещен, и поэтому вы не сможете использовать его позже.

File::open принимает любые AsRef<Path> , и поэтому вы можете передать ссылку на свой PathBuf (обратите внимание на amp; ):

 File::open(amp;filename)
  

Теперь он был заимствован, и вы можете использовать его позже в коде обработки ошибок.

Комментарии:

1. Теперь это имеет гораздо больше смысла! Спасибо; Комментарий Джона К. заставил меня попытаться понять, почему мой минимальный случай был таким разным, но я вижу, что это была небольшая ошибка. Я признаю, что мне немного неясно, что такое перемещение и заимствование (очевидно), но, надеюсь, я смогу найти хорошее руководство по этому вопросу в Интернете. Опция by-ref — это явно то, что я искал здесь!