Rust Nomicon有an entire section on variance,我或多或少都能理解,除了关于 Box<T>
和 Vec<T>
的这一小部分是 T
的(共)变体 .
Box和Vec是有趣的案例,因为它们是变体,但你绝对可以存储 Value !这就是Rust变得非常聪明的地方:它们很适合变种,因为你只能通过可变引用存储它们中的值!可变引用使整个类型不变,因此可以防止您将短期类型走私到它们中 .
令我困惑的是以下几行:
它们很适合变种,因为你只能通过可变引用存储它们中的值!
我的第一个问题是,我对可变引用的含义感到有些困惑 . 它是 Box
/ Vec
的可变引用吗?
如果是这样,那么我只能通过可变参考在其中存储值的事实如何证明它们的(共)方差?我理解(共)方差是什么以及将它用于 Box<T>
, Vec<T>
等等的好处,但我很难看到只能通过可变引用存储值与(共)方差的理由之间的联系 .
另外,当我们初始化一个 Box
时,这是否与我们只能通过可变引用存储值的声明相矛盾?
最后,在什么情况下借这个_982138?它们是否意味着当您调用修改 Box
或 Vec
的方法时,您隐含地采用 &mut self
?这是提到的可变参考吗?
Update 2nd May 2018 :
由于我还没有得到这个问题的满意答案,我认为这个nomicon的解释真的令人困惑 . 正如在下面的评论帖中所承诺的那样,我已经打开了an issue in the Rust Nomicon repository . 您可以跟踪那里的任何更新 .
4 回答
我认为该部分可以使用一些工作来使其更清晰 .
不 . 这意味着,如果您将值存储在现有的
Box
中,则必须通过对数据的可变引用来执行此操作,例如使用Box::borrow_mut()
.本节试图传达的主要思想是,当存在对内容的另一个引用时,您无法修改
Box
的内容 . 这是有保证的,因为Box
拥有其内容 . 为了更改Box
的内容,您必须通过采用新的可变引用来实现 .这意味着 - 即使你用较短的值覆盖内容 - 也没关系,因为没有其他人可以使用旧的值 . 借款检查员不会允许 .
这与函数参数不同,因为函数有一个代码块,它实际上可以用它的参数做事 . 在
Box
或Vec
的情况下,您必须通过可变地借用它们来获取内容,然后才能对它们执行任何操作 .来自nomicom:
考虑使用
Vec
方法添加值:self的类型是
&'a mut Vec<T>
,我理解这是nomicom所说的可变引用,所以为Vec
case实例化上述短语的最后一句变为:类型
&'a mut Vec<T>
是不变的,因此可以防止您将短期类型走私到Vec<T>
中 .Box的理由相同 .
换句话来说:
Vec
和Box
包含的值总是比它们的容器寿命更长,尽管Vec
和Box
是变体,因为你只能通过可变引用将值存储在它们中 .请考虑以下代码段:
它应该有助于注意
Vec::push(&mut v, &mut a_value)
与overwrite(&mut forever_str, &mut &*string)
与nomicom示例的相似性 .我想重点是,虽然你可以将
Box<&'static str>
转换为Box<&'a str>
(因为Box<T>
是协变的),但你不能将&mut Box<&'static str>
转换为&mut Box<&'a str>
(因为&mut T
是不变的) .自从在Nomicon回购中打开这个问题以来,维护人员已经介绍了一个revision to the section,我觉得这个问题要清楚得多 . 修订已合并 . 我认为修改后回答了我的问题 .
下面我简要总结一下我所知道的内容 .
与我的问题相关的部分现在如下(强调我的):
这里的关键点实际上是
&mut Vec<T>
在T
上的不变性与&mut T
在T
上的不变性之间的平行关系 .之前在修订后的nomicon部分解释了为什么一般
&mut T
不能在T
上进行协变 .&mut T
借用T
,但它不拥有T
,这意味着还有其他东西引用T
并对其生命周期有一定的期望 .但是如果允许我们通过
T
传递&mut T
协变,那么nomicon示例中的overwrite
函数显示了我们如何从不同的位置(即overwrite
体内)打破调用者位置T
的生命周期 .从某种意义上说,允许一个类型构造函数的
T
的协方差允许我们'忘记T
的原始生命周期___忘记T
的原始生命周期'对于&T
是可以的,因为我们没有机会通过它修改T
,但它很危险我们有一个&mut T
因为我们能够在忘记生命周期细节之后修改T
. 这就是&mut T
需要在T
上不变的原因 .It seems the point the nomicon is trying to make is: it's OK for Box<T> to be covariant over T because it does not introduce unsafeness.
这种协方差的一个后果是,当按值传递
Box<T>
时,我们被允许'忘记T
'的原始生命周期 . 但是这并没有引入不安全因素,因为当我们通过值传递时,我们保证在Box<T>
被移动的位置没有T
的其他用户 . 在旧的位置上没有其他人指望在移动之后保持这样的前一生命T
.但更重要的是,
Box<T>
在T
上的协变性并没有引入不可靠性,因为&mut Box<T>
在Box<T>
上是不变的,因此在T
上不变 . 因此,类似于上面的&mut T
讨论,我们无法通过忘记T
的生命周期详细信息然后在之后修改它来执行&mut Box<T>
的终生恶作剧 .