子类型和方差(&mut不变)违反rust中的错误

r6vfmomb  于 2022-11-12  发布在  其他
关注(0)|答案(1)|浏览(129)
fn main() {
    struct Foo<'a, T> {
        a: &'a mut T,
    }

    let p1 = 1;
    let mut p2 = &p1;
    {
        let p3 = 2;
        let mut p4 = &p3;
        let mut f = Foo {
            a: &mut p4,
        };
        f.a = &mut p2;
        println!("{}", f.a);
    }
    println!("{}", p2);
}

运行此程序时,遇到如下错误:
第一个
这是我第一个问题:为什么会存在这些错误?
如果我注解最后一行,例如:

fn main() {
    struct Foo<'a, T> {
        a: &'a mut T,
    }

    let p1 = 1;
    let mut p2 = &p1;
    {
        let p3 = 2;
        let mut p4 = &p3;
        let mut f = Foo {
            a: &mut p4,
        };
        f.a = &mut p2;
        println!("{}", f.a);
    }
    // println!("{}", p2);
}

通过引用rustonomicon

f.a = &mut p2;

&'a mut T在'a上是协变的,在T上是不变的,它应该编译不成功。但是编译成功了,为什么?
如果我注解最后一行,它应该编译不成功。

tf7tbtn2

tf7tbtn21#

问题的核心是f有一个固定类型Foo<'a, &'b i32>,并且根据可变引用的方差规则,&'b i32是不变的,因此'b是不变的。
但是,f通过p2p4T一起作为两个独立的生存期使用。编译器如何选择?它不能将p2使用的生存期缩短为p4使用的生存期。因为p2可以被修改以引用更短寿命的某个东西(考虑一下,如果在将f.a赋值给&mut p2之后立即添加*f.a = &p3;,将会发生什么情况)。唯一的选择是将p4使用的生存期扩展到与p2匹配。
由于p4必须与p2的生存期匹配,因此来自p3的赋值现在太短了,所以您会得到所看到的错误。
第二个示例有效,因为p2使用的生存期不会在内部块中的println!之后延长,因此p3可以满足该生存期。

相关问题