需要在``box'',``vec''和其他集合的(CO)方差的Rust Nomicon部分上进行澄清



RUST NOMICON具有整个方差的部分,除了Box<T>Vec<T>的这个小部分,我或多或少地理解了T上的(CO(变体。

BoxVec是有趣的情况,因为它们的变体,但是您绝对可以将值存储在其中!这是Rust变得非常聪明的地方:对他们来说,变体是可以的,因为您只能通过可突出的参考将其存储在它们中的中!可变的参考使整个类型不变,因此阻止您将短暂的类型走私到其中。

让我感到困惑的是以下行:

可以使他们成为变体是可以的,因为您只能通过可变的参考!

存储中的值

我的第一个问题是,我对可变参考的意思有些困惑。它是对Box/Vec的可变引用吗?

如果是这样,我只能通过可变参考来存储它们的值的事实证明其(CO(差异是合理的?我了解(CO(方差是什么以及为Box<T>Vec<T>等拥有它的好处,但是我正在努力看到仅通过可变引用来存储值与(CO(方差的正当值之间的链接。p>同样,当我们初始化 Box时,如果不涉及可变参考的情况,则值不是将值移入框中吗?这是否与我们只能通过可变参考存储在其中值的陈述不矛盾?

最后,在哪个上下文中,借用了"可变参考"?它们是指调用修改BoxVec的方法时,您会隐式服用&mut self?是提到的可变参考吗?


更新2018年5月2日

由于我还没有对这个问题获得令人满意的答案,所以我认为提名的解释确实令人困惑。因此,正如下面的评论主题中所承诺的那样,我在Rust Nomicon存储库中开了一个问题。您可以跟踪那里的任何更新。

我认为该部分可以使用一些工作来清晰。

我对可变参考的内容有些困惑。它是对盒子/vec的可变引用吗?

否。这意味着,如果将值存储在现有的 Box中,则必须通过对数据的可变引用来执行此操作,例如使用Box::borrow_mut()

本节试图传达的主要思想是,您不能修改 Box的内容,而另有提到了内容。这是可以保证的,因为Box拥有其内容。为了更改Box的内容,您必须通过获取新的可变参考。

这意味着 - 即使您确实以较短的价值覆盖了内容,也没关系,因为没有人可以使用旧值。借用检查器不允许它。

这与函数参数不同,因为一个函数具有一个代码块,该代码块实际上可以用其参数来完成事情。对于BoxVec,您必须通过对它们做任何事情,然后才能借用它们。提名:

Box和VEC是有趣的情况,因为它们的变体,但是您绝对可以在其中存储值!这是Rust变得非常聪明的地方:对他们来说,变体是可以的,因为您只能通过可变的参考来存储它们的值!可变的参考使整个类型不变,因此阻止您将短暂的类型走私到其中。

考虑添加值的Vec方法:

pub fn push(&'a mut self, value: T)

自我的类型是 &'a mut Vec<T>,我知道这是可见参考的提名正在谈论的是,因此对Vec案例进行实例化上述短语的最后一句话:

类型&'a mut Vec<T>是不变的,因此阻止您将短暂的类型走私到Vec<T>中。

框相同的推理。

以另一种方式说:尽管VecBox是变体,VecBox所包含的值始终超过容器,因为您只能通过可突出的参考将其存储在它们中。

考虑以下片段:

fn main() {
    let mut v: Vec<&String> = Vec::new();
    {
        let mut a_value = "hola".to_string();
        //v.push(a_ref);
        Vec::push(&mut v, &mut a_value);
    }
    // nomicom is saing that if &mut self Type was variant here we have had
    // a vector containing a reference pointing to freed memory
    // but this is not the case and the compiler throws an error
}

应该有助于从"提名示例"中注意到Vec::push(&mut v, &mut a_value)overwrite(&mut forever_str, &mut &*string)的相似性。

以来,自提名库中打开问题以来,维护者已经对该部分进行了修订,我认为这很清楚。修订已合并。我认为我的问题是通过修订回答的。

下面我提供了我所知道的简要摘要。

与我的问题有关的部分如下(重点是我的(:

BoxVec是有趣的情况,因为它们协变了,但是你 绝对可以将价值存储在其中!这是Rust的典型系统 允许它比其他人更聪明。了解为什么 拥有容器在其内容上是协变量的声音,我们 必须考虑可能发生突变的两种方式:附带或 参考。

如果突变是副价值,则记得额外的旧位置 详细信息已移出,这意味着它不能再使用该值。所以我们 根本不必担心有人会记住危险的细节。 换句话说,通过价值破坏时应用子类型 永远的细节。例如,此编译且很好:

 fn get_box<'a>(str: &'a str) -> Box<&'a str> {
     // String literals are `&'static str`s, but it's fine for us to
     // "forget" this and let the caller think the string won't live that long.
     Box::new("hello") }

如果突变是引用,则我们的容器作为&mut Vec<T>传递。但是&mut在其上不变 值,因此&mut Vec<T>实际上是在T上不变的。所以事实 Vec<T>在突变时对T的协变量无关紧要 参考。

这里的要点确实是T&mut Vec<T>的不变性与T上的不变性&mut T之间的平行。

在修订的名称部分中进行了早期解释,为什么一般&mut T不能在T上进行协变。&mut T借用T,但它不拥有T,这意味着还有其他内容是指T,并且对其寿命有一定的期望。

但是,如果我们被允许通过 &mut T通过T通过CC_49,则名nICON示例中的overwrite功能显示了我们如何在呼叫者的位置中打破T的寿命 一个不同的位置(即overwrite的主体(。

从某种意义上说,允许在T上使用类型构造函数的协方差使我们可以在传递类型构造函数时"忘记T的原始寿命",并且"忘记T的原始寿命"是可以的,因为没有&T,因为没有我们可以通过它修改T的机会,但是当我们拥有&mut T时,这很危险,因为我们有能力修改 T 忘记了有关它的终身详细信息。这就是为什么&mut T需要在T上不变。

似乎提名要提出的重点是:Box<T>可以通过T进行协变,因为它不引入不安全。

这种协方差的后果之一是,当按值传递Box<T>时,我们可以忘记"忘记T的原始寿命"。但这不会引入不安全,因为当我们按价值传递时,我们保证在Box<T>移动的位置中没有其他T用户。旧位置中没有其他人依靠T的前一生,以免移动后。

,但更重要的是,在T上是协变量的Box<T>在对Box<T>进行可变的参考时不会引入不安全,因为&mut Box<T>Box<T>上是不变的,因此在T上是不变的。因此,类似于上面的&mut T讨论,我们无法通过忘记有关T的终身详细信息,然后在以后对其进行修改。

我想重点是,虽然您可以将Box<&'static str>转换为Box<&'a str>(因为Box<T>是协变量(,但您不能将&mut Box<&'static str>转换为&mut Box<&'a str>(因为&mut T是不变的(。

>

最新更新