使用盒装特质对象时,生锈的生命规则是什么?
下面的代码不会与ERROR E0597编译:借用的值(两个)寿命不够长。
fn main() {
let one = String::from("one");
let mut _it: Box<dyn Iterator<Item=char>> = Box::new(one.chars());
let two = String::from("two");
_it = Box::new(two.chars());
}
但是,如果我使用对特征对象的引用而不是盒装特质对象,它可以工作:
fn main() {
let one = String::from("one");
let mut _it: &dyn Iterator<Item=char> = &one.chars();
let two = String::from("two");
_it = &two.chars();
}
另外,如果我不使用特质对象,它也可以工作:
fn main() {
let one = String::from("one");
let mut _it: Box<_> = Box::new(one.chars());
let two = String::from("two");
_it = Box::new(two.chars());
}
为什么?
The code below doesn't compile with error E0597: borrowed value (two) doesn't live long enough.
fn main() {
let one = String::from("one");
let mut _it: Box<dyn Iterator<Item=char>> = Box::new(one.chars());
let two = String::from("two");
_it = Box::new(two.chars());
}
But, if instead of boxed trait object I use reference to a trait object it works:
fn main() {
let one = String::from("one");
let mut _it: &dyn Iterator<Item=char> = &one.chars();
let two = String::from("two");
_it = &two.chars();
}
Also, if I don't use trait object it works too:
fn main() {
let one = String::from("one");
let mut _it: Box<_> = Box::new(one.chars());
let two = String::from("two");
_it = Box::new(two.chars());
}
Why?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
让我们一个一个一个。
在您的第一个示例中,该问题是微妙的,并由错误消息暗示
,如说明所示,值以相反的顺序删除。由于
两个
在第6行中定义,_it
在第4行中定义了(未分配的分配),编译器将尝试销毁两个
在函数结束时试图销毁_it
之前。但是到我们到达函数结束时,_IT
保留对两个
(第8行)的引用,而施加的订购将销毁两个
两个_IT
仍然对其进行引用。_IT
的攻击子可以观察销毁的值两个
,因此不允许使用。为什么甚至有攻击者?因为特征对象
dyn Iterator ...
- 就像任何其他特征对象一样 - 可以 都可以容纳具有击振子的动态类型。灾难可能会观察到它可能参考的事物。据编译器所知,这是两个
。尽管实际chars
-Type不会遭受此问题的困扰,但我可以召集这种类型并将其粘在dyn Iterator ...
中。因此,使用性状对象,删除值的顺序始终很重要。解决方案是更改定义顺序:
在第二个示例中,您使用普通参考。由于普通引用没有破坏者,因此没有可能在运行时可能会观察到被破坏的价值,而被破坏的顺序并不重要。因此,它可以很好地编译。
在第三个示例中,不涉及性格对象,就编译器而言,盒装类型只是一种普通类型(就像
box&lt; u32&gt;
)一样。因为它是一种具体的类型,所以编译器可以找出box
内的类型(这是chars
,并保留某些寿命的引用),具有琐碎destructor(无用),因此box
具有简单地交易的微不足道驱动器;因此,两个
实际上在_IT
之前被摧毁并不重要,因为_IT
肯定不会观察到两个
两个< /code>在其破坏者中。
Let's take them one by one.
In your first example, the problem is subtle and hinted at by the error message
As the note says, values are dropped in the opposite order they are defined. As
two
is defined in line 6 and_it
is defined (not assigned) in line 4, the compiler will try to destroytwo
before it tries to destroy_it
at the end of the function. But by the time we reach the end of the function,_it
holds a reference totwo
(line 8), and the imposed ordering would destroytwo
while_it
still holds a reference to it. The destructor of_it
could observe the destroyed valuetwo
, so this is not allowed.Why is there even a destructor? Because the trait object
dyn Iterator...
- just like any other trait object - could hold some dynamic type that has a destructor. And that destructor might observe things it potentially references; as far as the compiler knows, that'stwo
. While the actualChars
-type does not suffer from this problem, I could conjure up such a type and stick it into adyn Iterator...
. So with trait objects, the order in which values are dropped is always important.The solution is to change the order of definition:
In the second example, you are using plain references. Since plain references do not have destructors, there is no destructor that could potentially observe a destroyed value while it is running, and the order in which values are destroyed is not important; so it compiles just fine.
In the third example, there are no trait objects involved, the boxed type is simply a normal type as far as the compiler is concerned (just like
Box<u32>
). Because it is a concrete type, the compiler can figure out that the type inside theBox
(which is aChars
, and holds a reference of some lifetime), has a trivial destructor (which does nothing), and therefore theBox
has a trivial destructor that simply deallocates; so it doesn't matter thattwo
is in fact destroyed before_it
, because_it
will definitely not be able to observetwo
in its destructor.