为什么在可变变量上调用方法会导致其值被移动?

问题描述

我使用 http::Request::builder() 创建请求并使用 uri() 设置请求 uri。 以下代码编译没有问题:

fn get_oauth_token() {
    let mut request = Request::builder().uri(&*OAUTH_URL);
    let uri = match request.uri_ref() {
        Some(uri) => uri.to_string(),None => String::from(""),};
    println!("{}",uri)
}

但是,如果我先声明变量 request 并对该变量调用 uri() 方法,我会收到如下所示的错误

fn get_oauth_token() {
    let mut request = Request::builder();
    request.uri(&*OAUTH_URL);
    let uri = match request.uri_ref() {
        Some(uri) => uri.to_string(),uri)
}
error[E0382]: borrow of moved value: `request`
 --> src\main.rs:9:21
  |
7 |     let mut request = Request::builder();
  |         ----------- move occurs because `request` has type `http::request::Builder`,which does not implement the `copy` trait
8 |     request.uri(&*OAUTH_URL);
  |     ------- value moved here
9 |     let uri = match request.uri_ref() {
  |                     ^^^^^^^ value borrowed here after move

请注意,这两个片段之间的唯一区别是我将行 let mut request = Request::builder().uri(&*OAUTH_URL); 拆分为 let mut request = Request::builder();request.uri(&*OAUTH_URL);

变量 OAUTH_URL 声明如下(我使用 dotenv 从 .env 文件加载它):

lazy_static! {
    static ref OAUTH_URL: String = env::var("OAUTH_URL").unwrap();
}

现在我查看了错误 E0382 的解释,它告诉我如果将变量的值分配给另一个有意义的变量,它的值将被移动。但是,我不明白为什么在这种情况下会发生这种情况,因为我只声明了一个变量,然后在该变量上调用一个方法

为什么当我调用 requestrequest.uri(&*OAUTH_URL); 的值会移动?

解决方法

根据documentation,该方法移动对象,然后将其返回。所以这两个片段是非常不同的。

第一个片段是正确的方式,因为值在链中移动并存储在 request 中;完全可以接受!在另一个片段中,request.uri(&*OAUTH_URL); 将值移动到方法中,然后将对象扔掉,即您刚刚消耗并丢弃了对象。

要使它们相等,您必须编写 request = request.uri(&*OAUTH_URL);

第一个片段(正确):

fn get_oauth_token() {
    // Object moves from Request::builder() -> .uri(&*OAUTH_URL) -> request
    let mut request = Request::builder().uri(&*OAUTH_URL);
    let uri = match request.uri_ref() {
        Some(uri) => uri.to_string(),None => String::from(""),};
    println!("{}",uri)
}

第二个片段(错误):

fn get_oauth_token() {
    // Object moves from Request::builder() -> request
    let mut request = Request::builder();
    // Object moves from request -> .uri(&*OAUTH_URL) -> nowhere
    request.uri(&*OAUTH_URL);
    let uri = match request.uri_ref() {
        Some(uri) => uri.to_string(),uri)
}

备用片段(正确):

fn get_oauth_token() {
    // Object moves from Request::builder() -> request
    let mut request = Request::builder();
    // Object moves from request -> .uri(&*OAUTH_URL) -> request again
    request = request.uri(&*OAUTH_URL);
    let uri = match request.uri_ref() {
        Some(uri) => uri.to_string(),uri)
}