【问题标题】:How to make a struct where one of the fields refers to another field如何制作其中一个字段引用另一个字段的结构
【发布时间】:2014-11-23 17:56:14
【问题描述】:

我有以下问题:我有一个从缓冲区解析并包含对该缓冲区的一些引用的数据结构,因此解析函数看起来像

fn parse_bar<'a>(buf: &'a [u8]) -> Bar<'a>

到目前为止,一切都很好。但是,为了避免某些生命周期问题,我想将数据结构和底层缓冲区放入一个结构中,如下所示:

struct BarWithBuf<'a> {bar: Bar<'a>, buf: Box<[u8]>}
// not even sure if these lifetime annotations here make sense,
// but it won't compile unless I add some lifetime to Bar

但是,现在我不知道如何实际构造一个BarWithBuf 值。

fn make_bar_with_buf<'a>(buf: Box<[u8]>) -> BarWithBuf<'a> {
    let my_bar = parse_bar(&*buf);
    BarWithBuf {buf: buf, bar: my_bar}
}

不起作用,因为 buf 在 BarWithBuf 值的构造中被移动了,但我们借用它进行解析。

我觉得应该可以做一些类似的事情

fn make_bar_with_buf<'a>(buf: Box<[u8]>) -> BarWithBuf<'a> {

    let mut bwb = BarWithBuf {buf: buf};
    bwb.bar = parse_bar(&*bwb.buf);
    bwb
}

为了避免在解析Bar 后移动缓冲区,但我不能这样做,因为必须一次性初始化整个BarWithBuf 结构。 现在我怀疑我可以使用unsafe 代码来部分构造结构,但我宁愿不这样做。 解决这个问题的最佳方法是什么?我需要不安全的代码吗?如果我这样做,在这里这样做是否安全?还是我完全走错了轨道,有更好的方法将数据结构及其底层缓冲区联系在一起?

【问题讨论】:

  • 我从来没有想过是否可以在没有不安全代码的情况下对结构的其他成员进行内部引用。我看不出借用检查器如何跟踪像这样的借用...
  • 这个问题已经够老了,我不想将其作为重复项关闭,但大多数访问此问题的人可能应该查看Why can't I store a value and a reference to that value in the same struct?

标签: rust


【解决方案1】:

我认为你是对的,没有不安全的代码就不可能做到这一点。我会考虑以下两种选择:

  1. Bar 中的引用更改为索引。盒子的内容不会被借用保护,所以如果你不小心,索引可能会变得无效。但是,索引可能会以更清晰的方式传达引用的含义。

  2. Box&lt;[u8]&gt;移动到Bar,并在Bar的实现中添加一个函数buf() -&gt; &amp;[u8];将索引存储在Bar 中,而不是引用。现在Bar 是缓冲区的所有者,因此它可以控制其修改并保持索引有效(从而避免选项#1 的问题)。

  3. 1234563 -苍蝇。

哪些选项最合适取决于实际的问题上下文。我同意某种形式的“逐个成员构造”结构对 Rust 非常有帮助。

【讨论】:

  • 我考虑过第一个选项,但我不是特别喜欢它。我无法理解您的第二个建议,您能否详细说明一下?
  • @fjh 我相信 Adrian 建议您将 Box 包装在一个类型中,该类型具有返回临时 Bar 的方法。这个想法是您存储Bar 的“可移植”形式(如装箱数据中的索引),并且该方法按需构造Bar,使用&amp;self 的生命周期来保证安全。
  • @DK。不完全是,但我澄清了选项 #2 并将您的建议添加为选项 #3。
  • 谢谢!我可能会硬着头皮使用StringVec,而不是引用缓冲区来回避整个问题。基于索引的解决方案感觉有点笨拙,并且对我来说并不适用,因为缓冲区中的一些引用是&amp;str,所以我必须反复验证 utf 编码或使用不安全的代码。
猜你喜欢
  • 1970-01-01
  • 2015-01-17
  • 1970-01-01
  • 2021-12-28
  • 2021-11-01
  • 2014-07-06
  • 1970-01-01
  • 2023-01-01
  • 1970-01-01
相关资源
最近更新 更多