我之前在看 nomicon 的 Drop Check 章节,但是马上就被第一个例子难住了,以下是一个简化的版本:
struct U8RefWithDrop<'a>(&'a u8);
impl<'a> Drop for U8RefWithDrop<'a> {
fn drop(&mut self) {}
}
struct AStruct<'a> {
u8ref: U8RefWithDrop<'a>,
u8val: u8,
}
fn main() {
let mut a = AStruct {
u8val: 42,
u8ref: U8RefWithDrop(&0),
};
a.u8ref = U8RefWithDrop(&a.u8val);
}
既然 RFC 1857 定义了 struct
中 fields 的 drop 顺序,例子里的 AStruct
也没有实现自定义的 Drop
(如果有实现,Drop
函数中就可以按随机顺序 Drop 掉各 fields),那么为什么编译器仍要考虑 u8val
在 u8ref
的 Drop
函数被调用之前就被 Drop 掉这种情况呢?
1
共 2 条评论, 1 页
评论区
写评论对你的问题,从这段话找出几个重点(因为这段话是紧跟你的例子,你并没有理解):
<>
尖括号里的东西,有生命周期参数、类型参数、常量参数。)generic type: A generic type is a type with a generic parameter.
generic parameter: A generic parameter is a placeholder for a constant, a lifetime, or a type whose value is supplied statically by a generic argument.
如果泛型类型不是泛型,那么这个类型只有
'static
生命周期,它才真正活永远。(不是泛型,等价于不含泛型参数,当然无生命周期参数,从而不含借用;活永远,指想让它活多久就活多久,但需要考虑所有权)dropck 更深入的细节仍未确定。(Rust 采取保守的策略,只要在 safe Rust 中有可能出现不安全的情况,都不允许,除非使用 unsafe)
大原则是确定的:泛型类型安全地实现 drop,其泛型参数必须严格活得比这个泛型类型长!例子
怎么解决呢?文章后半部分就在说这个事。
比如,你可以使用
#[may_dangle]
,注意这是 unsafe 的。使用#[may_dangle]
的前提:#[may_dangle]
用于保证 drop 函数不访问该借用 。如果你违反这个保证,代码是 UB。使用 run 和 miri 运行这个 例子,虽然表面上看代码正常运行,其实已经因为 unsafe 引入了 unsound。一个常见的做法是手动 drop,使用 ManuallyDrop,miri 通过,注意
ManuallyDrop::drop
仍是 unsafe,你自己保证代码安全。推荐我看到的一篇好的 dropck 文章(中文原创):https://ng6qpa7sht.feishu.cn/docx/LGnVdlqwGoIUpuxUMWRcptEbndd