Структура с частичными ошибками перемещения - PullRequest
0 голосов
/ 17 октября 2019

У меня есть простая структура и два ее экземпляра, как показано ниже:

#[derive(Debug)]
struct User {
    first: String,
    last: String,
    age: u32,
}

let u1 = User {
    first: String::from("John"),
    last: String::from("Doe"),
    age: 22,
};

let u2 = User {
    first: String::from("Mary"),
    ..u1
};

println!("user: {:#?}", u1);

Сообщение об ошибке:

error[E0382]: borrow of moved value: `u1`
  --> src/main.rs:20:29
   |
15 |       let u2 = User {
   |  ______________-
16 | |         first: String::from("Mary"),
17 | |         ..u1
18 | |     };
   | |_____- value moved here
19 | 
20 |       println!("user: {:#?}", u1);
   |                               ^^ value borrowed here after partial move
   |
   = note: move occurs because `u1.last` has type `std::string::String`, which does not implement the `Copy` trait

Я попытался изменить его на ..&u1 в надеждепередаст проверку заимствования, чтобы я мог распространяться в базовой структуре (u1) на u2, но безрезультатно, интересно, возможно ли вообще то, что я хотел сделать здесь?

Я понимаю, это потому, что u1.last это String, следовательно, необходимо передать ссылку, но я не уверен, как заставить это работать в этом сценарии.

1 Ответ

0 голосов
/ 17 октября 2019

Ваш тип User содержит тип String, который владеет имеющимися у него строковыми данными (и не подразумевает Copy), поэтому два пользователя не могут указывать на одно и то же имя в памяти.

Решение, которое вы, вероятно, захотите:

#[derive(Debug, Clone)]
struct User {
    first: String,
    last: String,
    age: u32,
}

fn main() {
    let u1 = User {
        first: String::from("John"),
        last: String::from("Doe"),
        age: 22,
    };

    let u2 = User {
        first: String::from("Mary"),
        ..u1.clone() // Copy the strings into the new user 
        // (it also copies first, which is then thrown away? Maybe the compiler optimizes this away)
    };

    println!("user: {:#?}", u1);

}

, но если вы действительно хотите, чтобы два пользователя указывали на одно и то же имя в памяти (уверен, что нет), есть параиз опций:

  • Вы можете изменить String на &'static str. Это, однако, означает, что вы должны указать это при компиляции. (Вы не можете иметь тип пользователя в своем имени во время выполнения и сохранять его в пользователе)

    #[derive(Debug)]
    struct User {
        first: &'static str,
        last: &'static str,
        age: u32,
    }
    
    fn main() {
        let u1 = User {
            first: "John",
            last: "Doe",
            age: 22,
        };
    
        let u2 = User {
            first: "Mary",
            ..u1
        };
    
        println!("user: {:#?}", u1);
    }
    
    
    • Вы можете использовать Rc, чтобы отслеживать ссылки на фрагментПамять. Таким образом, вам не нужно беспокоиться о жизни и о том, кто чем владеет. (Достигается небольшая стоимость выполнения)
    use std::rc::Rc;
    
    #[derive(Debug, Clone)]
    struct User {
        first: Rc<String>,
        last: Rc<String>,
        age: u32,
    }
    
    fn main() {
        let u1 = User {
            first: Rc::new(String::from("John")),
            last: Rc::new(String::from("Doe")),
            age: 22,
        };
    
        let u2 = User {
            first: Rc::new(String::from("Mary")),
            ..u1.clone() // Clone the references, not the actual string. For strings with just a couple characters, the time difference is completely negligible)
        };
    
        println!("user: {:#?}", u1);
    }
    
    • Используйте взамен Rc<Mutex<String>>, если вы хотите изменить имя позже и изменить его на u1 и u2.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...