引用在其引用的对象被删除后多长时间保持有效?
How long does a reference remain valid after the object it references is dropped?
我正在阅读 Common Rust Lifetime Misconceptions 来弄清楚生命周期是如何运作的,其中一个例子(在下面发布)真的让我震惊,
我无法说服自己为什么 byte_1
和 byte_2
在 std::mem::drop(bytes);
被执行后仍然活得很好。
从我的角度来看,byte_1
和 byte_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_1
和 byte_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 可变引用。
我正在阅读 Common Rust Lifetime Misconceptions 来弄清楚生命周期是如何运作的,其中一个例子(在下面发布)真的让我震惊,
我无法说服自己为什么 byte_1
和 byte_2
在 std::mem::drop(bytes);
被执行后仍然活得很好。
从我的角度来看,byte_1
和 byte_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_1
和 byte_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 可变引用。