【问题标题】:How can I take ownership of a value, passing a reference to an external API?如何获得一个值的所有权,将引用传递给外部 API?
【发布时间】:2016-05-17 21:21:26
【问题描述】:

我有一个外部类型 (protobuf:::CodedInputStream),它期望引用一个被引用的 trait-object (TcpStream as &mut Read)。

我想制作一个类型或函数Connection 包装TcpStream(获取所有权)和CodedInputStream,以便使用它的功能,将 TcpStream 的使用和所有权封装为内部详细。

但是,我不知道怎么做。我的天真尝试(伪生锈)

struct Connection {
    stream: TcpStream,
    coded_stream: CodedInputStream,
}

fn new_connection(s: TcpStream) -> Connection {
    Connection {
        stream: s,
        // Invalid, `s` has been transferred to `stream` above
        coded_stream: CodedInputStream::new(&mut s),
        // Invalid, `stream` is an unresolved symbol here
        coded_stream: CodedInputStream::new(&mut stream),
        // Omitting and mutating fails, since `coded_stream`
        // must have a value and there is no "0"-value.
    }
}

我是否遗漏了一些明显的东西?这在 Rust 中通常是一个坏主意吗?是否有其他模式来处理获取所有权和封装长寿命对象?

Why can't I store a value and a reference to that value in the same struct? 中有一个类似的问题涉及如何重构内部类型以解决问题。在这里,CodedInputStream 不在我的控制范围内,需要不同的解决方案(我相信)。

【问题讨论】:

  • [do] 不要尝试将这些项目放在同一个结构中 — 似乎这同样适用于您的情况?您尝试使用owning_ref 的结果是什么?
  • 它实际上并没有说不要尝试。它说最简单和最推荐的解决方案是不要尝试....问题是它确实不适用于我的情况,因为我无法更改外部 API。这类似于“无法完成,因为这不是 rust 的工作方式”的答案,这很好,但它仍然不是同一个问题,因为我的问题仍然涉及外部 API。
  • OwningRef 很接近,但我意识到(我在我的问题中错过了这一点)CodedInputStream 需要一个可变引用。 AFAIU,OwningRef 只能处理不可变的值?
  • 另一个问题中提出的解决方案需要重新设计 B,这样就不需要引用 A — 也许我的其他答案过于混乱了;我并不是建议您将外部类型分开。我建议您在上面的代码中拆分包含类型Connection[我想创建]单个封装值——没错,当一个封装值引用另一个时,你不能这样做。这就是重复问题的全部意义所在。
  • FWIW,我对 protobuf 库了解不多,但 InputSource 类型似乎不优雅。我本来希望InputSource 成为您必须满足的特征,并且枚举中可能有用于 3 个事物的内置适配器。那将解决整个问题。其实someone else might agree that it should be changed,虽然那是输出,不是输入。

标签: rust lifetime


【解决方案1】:

你不能这样做,因为在 Rust 的所有权规则下它是不安全的。

这是一个自引用结构。自引用结构有两个问题:

  • 所有拥有的类型都可以随时移动到另一个内存地址,并且设计上总是像memcpy 一样简单,没有任何魔法。在您的情况下,这意味着一旦您返回Connectionstream 的地址就会改变,coded_stream 中的引用将变得悬空。

  • 借用检查器允许单独覆盖/替换结构字段。在您的情况下,这意味着它将允许 stream 被新的覆盖,从而使 coded_stream 出现 use-after-free 错误。

所以常规的借用检查规则不能表达同时拥有和借用的两个字段之间的特殊关系。

rental crate 为此类情况提供了一些解决方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-19
    • 1970-01-01
    • 2018-06-09
    • 1970-01-01
    • 2016-02-29
    • 1970-01-01
    • 2020-04-01
    • 1970-01-01
    相关资源
    最近更新 更多