引用在其引用的对象被删除后多长时间保持有效?

How long does a reference remain valid after the object it references is dropped?

我正在阅读 Common Rust Lifetime Misconceptions 来弄清楚生命周期是如何运作的,其中一个例子(在下面发布)真的让我震惊, 我无法说服自己为什么 byte_1byte_2std::mem::drop(bytes); 被执行后仍然活得很好。

从我的角度来看,byte_1byte_2 持有的引用在迭代器 bytes 被删除后应该是无效的,因为 remainder 数组被删除为好吧,编译器应该将 drop 操作视为错误,但实际上它通过了编译器并且运行没有问题...

希望C++/C#出身的程序员给个合理的解释,谢谢!

struct ByteIter<'remainder> {
    remainder: &'remainder [u8]
}

impl<'remainder> ByteIter<'remainder> {
    fn next(&mut self) -> Option<&'remainder u8> {
        if self.remainder.is_empty() {
            None
        } else {
            let byte = &self.remainder[0];
            self.remainder = &self.remainder[1..];
            Some(byte)
        }
    }
}

fn main() {
    let mut bytes = ByteIter { remainder: b"1123" };
    let byte_1 = bytes.next();
    let byte_2 = bytes.next();
    std::mem::drop(bytes); // we can even drop the iterator now!
    if byte_1 == byte_2 { // compiles
        // do something
    }
}

(学了一个月的Rust,还是被很多新概念弄糊涂了)

bytes 不拥有 b"1123"。它只有一个参考。因为没有所有权,所以删除 bytes 不会删除 b"1123"。删除 bytes 的引用不会影响具有相同生命周期的其他引用。

现在你可以使 byte_1byte_2 无效,如果你能以某种方式删除引用 b"1123"。但这是不可能的。 b"1123"'static 生命周期,并且 'static 对象不能被删除。

理解其工作原理的关键是查看 Iterator 的定义方式:

trait Iterator{
    type Item;
    fn next(&mut self)-> Option<Self::Item>;
}

请注意 return 值的生命周期如何与 Iterator 本身的生命周期无关。这意味着 returned 项目必须能够在没有原始 Iterator 的情况下生存。在这种情况下,索引操作重新借用与迭代器借用相同时间长度的原始对象*。这意味着只要您不尝试在 Iterator::next 编辑的 return 值在范围内时删除您借用的基础数据,编译器就不会抛出错误。在您的示例中,这不会发生,因为您正在迭代的内容嵌入在二进制文件本身中。在可以删除基础数据的情况下,it results in a compiler error if you try.

*这意味着抗锯齿规则要求在许多迭代器中使用不安全代码 returning 可变引用。