简体   繁体   中英

How to move one field out of a struct that implements Drop trait?

Here's an invalid Rust program (Rust version 1.1) with a function that does an HTTP client request and returns only the headers, dropping all other fields in the response.

extern crate hyper;

fn just_the_headers() -> Result<hyper::header::Headers, hyper::error::Error> {
    let c = hyper::client::Client::new();
    let result = c.get("http://www.example.com").send();
    match result {
        Err(e) => Err(e),
        Ok(response) => Ok(response.headers),
    }
}

fn main() {
    println!("{:?}", just_the_headers());
}

Here are the compiler errors:

main.rs:8:28: 8:44 error: cannot move out of type `hyper::client::response::Response`, which defines the `Drop` trait
main.rs:8         Ok(response) => Ok(response.headers),
                                 ^~~~~~~~~~~~~~~~
error: aborting due to previous error

I understand why the borrow checker doesn't accept this program—ie, that the drop function will use the response after it has had its headers member moved.

My question is: How can I get around this and still have good safe Rust code? I know I can do a copy , via clone() , like so:

Ok(response) => Ok(response.headers.clone()),

But, coming from C++, that seems inefficient. Why copy when a move should suffice? I envision in C++ doing something like the following to force a call to a move constructor, if available:

headers_to_return = std::move(response.headers);

Is there any way to forgo the copy in Rust and instead force a move , similar to C++?

You can use std::mem::replace() to swap the field with a new blank value in order to transfer ownership to you:

extern crate hyper;

fn just_the_headers() -> Result<hyper::header::Headers, hyper::error::Error> {
    let c = hyper::client::Client::new();
    let result = c.get("http://www.example.com").send();
    match result {
        Err(e) => Err(e),
        Ok(mut response) => Ok(std::mem::replace(&mut response.headers, hyper::header::Headers::new())),
    }
}

fn main() {
    println!("{:?}", just_the_headers());
}

Here, we're replacing response.headers with a new empty set of headers. replace() returns the value that was stored in the field before we replaced it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM