【问题标题】:How to give ownership inside Rust future如何在 Rust 未来中赋予所有权
【发布时间】:2019-07-27 15:55:14
【问题描述】:

我有一个 Rust 期货链,它需要在未来之外取得一个变量的所有权,但是,我不明白如何将变量的所有权传递给其中一个链。

问题似乎出在 'let domain = DNSNameRef::try_from_ascii_str(&address).unwrap()' 使用的 'address' 变量上,因为将 &address 替换为字符串即可。

我已经查找将变量放入 Arc/Mutex 和 Rc/RefCell 中,但它们似乎没有帮助(也许我只是做错了)。我觉得我明白我基本上需要将所有变量的所有权交给未来的闭包,因为它们的寿命会比当前的函数长,但我不知道如何做到这一点......

let address = inner.address().unwrap();

state.check_net(&address)?;

let op = resolve_addr(&address)
    .and_then(move |socket_address| {
      TcpStream::connect(&socket_address)
        .map_err(ErrBox::from)
    })
    .and_then(move |socket| {
      let mut config = ClientConfig::new();
      config
        .root_store
        .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
      let config = TlsConnector::from(Arc::new(config));
      let domain = DNSNameRef::try_from_ascii_str(&address).unwrap();
      config.connect(domain, socket)
        .map_err(ErrBox::from)
    })
    .and_then(move |tls_stream| new_tls_conn(cmd_id, tls_stream));
  if base.sync() {
    let buf = op.wait()?;
    Ok(Op::Sync(buf))
  } else {
    Ok(Op::Async(Box::new(op)))
  }

我得到的错误:

error[E0621]: explicit lifetime required in the type of `base`
    --> ../../cli/ops.rs:1748:18
     |
1716 |   base: &msg::Base<'_>,
     |         -------------- help: add explicit lifetime `'static` to the type of `base`: `&msg::Base<'static>`
...
1748 |     Ok(Op::Async(Box::new(op)))
     |                  ^^^^^^^^^^^^ lifetime `'static` required

【问题讨论】:

    标签: rust future lifetime


    【解决方案1】:

    我似乎已经通过使用address.to_owned() 克隆address 变量来使其工作,如下所示:

    let address = inner.address().unwrap();
    let domain = address.to_owned();
    
    state.check_net(&address)?;
    
    let op = resolve_addr(&address)
        .and_then(move |socket_address| {
          TcpStream::connect(&socket_address)
            .map_err(ErrBox::from)
        })
        .and_then(move |socket| {
          let mut config = ClientConfig::new();
          config
            .root_store
            .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
          let config = TlsConnector::from(Arc::new(config));
          let domain = DNSNameRef::try_from_ascii_str(&domain).unwrap();
          config.connect(domain, socket)
            .map_err(ErrBox::from)
        })
        .and_then(move |tls_stream| new_tls_conn(cmd_id, tls_stream));
    if base.sync() {
        let buf = op.wait()?;
        Ok(Op::Sync(buf))
    } else {
        Ok(Op::Async(Box::new(op)))
    }
    

    虽然我不太确定为什么会这样。如果有人能解释一下,将不胜感激!

    【讨论】:

    • Futures(从 0.1 版开始)不能很好地处理借来的数据,这正是您在这里遇到的原因。未来内的任何引用都必须是静态的,因为编译器无法静态跟踪未来内借用的生命周期。这是即将到来的 async/await 语法的主要动机之一,特别是“pinning”的概念,它允许借用可以跨越等待点。在 async/await 稳定之前,最简单的解决方法是执行您已完成的操作:通过复制/克隆确保期货拥有自己的数据。
    • 所以通过使用 address.to_owned(),我正在复制字符串,但是我不太明白为什么这意味着 Future 可以突然“拥有”数据。是不是因为地址在 resolve_address() 中被使用过一次,因此未来现在“拥有”它,然后在链中再次使用它就会把它扔掉?
    • 我不完全清楚局部变量 address 的类型是什么,但假设它是一个引用,在它上面调用 to_owned 会给你一个拥有相同数据的版本,通常通过复制/克隆它。当您在使用move 注释的闭包内使用address 时,值将从包含范围移动到闭包本身。然而,如果 address 本身是一个引用,那么闭包包含借用的数据,借用检查器目前无法在稳定的 Rust 中处理。
    • 这也有助于理解编译器将闭包“脱糖”成一个结构,该结构包含它从环境中捕获的所有值。所以在这种情况下,你有类似struct Closure123&lt;'a&gt; { address: &amp;'a Thing, ... } 的东西,这是借用检查器在异步代码中遇到的问题。通过将address 转换为一个拥有的值,闭包改为去糖化为struct Closure123 { address: Thing, ... },借用检查器对此没有任何问题。
    猜你喜欢
    • 1970-01-01
    • 2015-09-29
    • 1970-01-01
    • 2016-11-16
    • 1970-01-01
    • 1970-01-01
    • 2020-08-16
    • 2011-03-02
    • 2012-08-03
    相关资源
    最近更新 更多