2015-07-09 2 views
18

Hier ist ein ungültiges Rust-Programm (Rust-Version 1.1) mit einer Funktion, die eine HTTP-Client-Anfrage ausführt und nur die Header zurückgibt und alle anderen Felder in der Antwort löscht.Wie verschiebt man ein Feld aus einer Struktur, die Drop-Eigenschaft implementiert?

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()); 
} 

Hier sind die Compiler-Fehler:

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 

ich verstehen, warum die borrow checker dieses Programm nicht, dh nicht akzeptiert, dass die drop Funktion der response verwenden, nachdem er seine hatte headers Mitglied verschoben.

Meine Frage ist: Wie kann ich das umgehen und habe immer noch guten sicheren Rust-Code? Ich weiß, ich kann über clone() eine Kopie tun, etwa so:

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

Aber, die aus C++, die ineffizient zu sein scheint. Warum kopieren, wenn ein move sollte ausreichen? Ich sehe in C++, etwas zu tun wie die nach einem Aufruf zu einem Umzug Konstruktor zu zwingen, falls vorhanden:

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

Gibt es eine Möglichkeit, die Kopie in Rust zu verzichten und stattdessen zwingen, einen bewegen ähnlich C++?

Antwort

18

können Sie std::mem::replace() verwenden Sie das Feld mit einem neuen leeren Wert auszutauschen, um das Eigentum an Sie zu übertragen:

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()); 
} 

Hier sind wir response.headers mit einem neuen leeren Satz von Headern zu ersetzen. replace() gibt den Wert zurück, der in dem Feld gespeichert war, bevor wir es ersetzten.

+3

Es kann nichts wert sein, dass 'std :: mem :: replace 'in Rust ist * mehr oder weniger * was' std :: move' in C++ ist. Da die Quelle und das Ziel gültig sein müssen, um sowohl vor als auch nach einer Bewegung zu zerstören, bewegt sich C++ nicht wirklich, es wird ausgetauscht. –

+2

Mit dem Unterschied, dass in C++ die Klasse entscheidet, wie die Verschiebung implementiert wird (im Move-Konstruktor oder Move-Zuweisungsoperator), während "std :: mem :: replace" vom Aufrufer verlangt, einen geeigneten Wert anzugeben . Tatsächlich wird "std :: mem :: replace" in Form von "std :: mem :: swap" (http://doc.rust-lang.org/stable/std/mem/fn.swap) implementiert .html). –

+2

Vielleicht möchten Sie bemerken, dass Rust auch auf extrem effiziente "Standardkonstrukte" Wert legt, zum Beispiel weder 'String :: new()' noch 'Vec :: new()' allokieren Speicher, was diese ersetzt als Effizient, da sich C++ zusätzlich sicherer verhält. –

Verwandte Themen