【问题标题】:How to move one field out of a struct that implements Drop trait?如何将一个字段移出实现 Drop 特征的结构?
【发布时间】:2015-07-09 03:36:48
【问题描述】:

这是一个无效的 Rust 程序(Rust 1.1 版),其函数执行 HTTP 客户端请求并仅返回标头,丢弃响应中的所有其他字段。

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

以下是编译器错误:

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

我理解为什么借用检查器不接受这个程序——即,drop 函数将在其 headers 成员移动后使用 response。 p>

我的问题是:我怎样才能解决这个问题并且仍然拥有良好的安全 Rust 代码?我知道我可以通过clone() 进行复制,如下所示:

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

但是,来自 C++,这似乎效率低下。当 move 就足够时,为什么要 copy 呢?我设想在 C++ 中执行以下操作来强制调用移动构造函数(如果可用):

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

有没有什么办法可以放弃 Rust 中的 copy 而是强制 move,类似于 C++?

【问题讨论】:

标签: rust


【解决方案1】:

您可以使用std::mem::replace() 将字段替换为新的空白值,以便将所有权转让给您:

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

在这里,我们将response.headers 替换为一组新的空标题。 replace() 返回我们替换之前存储在字段中的值。

【讨论】:

  • Rust 中的 std::mem::replace或多或少与 C++ 中的 std::move 一样可能毫无价值。因为源和目标必须在移动之前都是有效的,所以C++并没有真正移动,它是交换的。
  • 确实,不同的是,在 C++ 中,是类决定如何实现移动(在移动构造函数或移动赋值运算符中),而 std::mem::replace 要求调用者提供合适的价值。其实std::mem::replace是按照std::mem::swap来实现的。
  • 您可能希望注意到,Rust 还强调极其高效的“默认构造”,例如,String::new()Vec::new() 都没有分配内存,这使得这个替换与C++ 更安全。
  • 谢谢!使用std::mem::replace 这个用例是惯用的吗? (我正在尝试做的事情——强制 move 而不是 copy——惯用语吗?)我问是因为对 std::mem::replace 的调用似乎很多打字做一些可能是常见用例的事情。
  • std::mem::replace 似乎是最合适的工具,可用于获取根据 Rust 的标准所有权规则无法拥有的值的所有权。不要忘记您可以使用 use 声明来缩短名称,例如use std::mem;,然后是mem::replace,或者use std::mem::replace,然后是replace。首选风格是使用模块上限定的函数 (mem::replace),但类型不限定 (Headers)。
猜你喜欢
  • 1970-01-01
  • 2021-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-17
  • 1970-01-01
相关资源
最近更新 更多