Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

rust

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—i.e., 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++?

like image 742
Craig M. Brandenburg Avatar asked Jul 09 '15 03:07

Craig M. Brandenburg


1 Answers

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.

like image 79
Francis Gagné Avatar answered Sep 22 '22 03:09

Francis Gagné