< 返回版块

bigteech 发表于 2021-10-11 10:51

Tags:borrowed


struct  Foo<'a> {
    h: &'a mut Vec<usize, &'a Bump>
}

pub fn s () {
    let s = Bump::new();
    {
        let mut bar = Vec::new_in(&s);

        {
            Foo {
                h: &mut bar,
            };
        }
    }

}

这个会产生错误

h: &mut bar,
    |                    ^^^^^^^^ borrowed value does not live long enough

struct  Foo<'a> {
    h: &'a Vec<usize, &'a Bump>
}

pub fn s () {
    let s = Bump::new();
    {
        let bar = Vec::new_in(&s);

        {
            Foo {
                h: &bar,
            };
        }
    }

}

这个就是好的,为什么

评论区

写评论
作者 bigteech 2021-10-11 19:36

--
👇
Bai-Jinlin: 你用的应该是bumpalo,那写成这样就行了,你生命周期本来就写的有问题。

struct Foo<'a, 'bump: 'a> {
    h: &'a mut Vec<'bump, usize>,
}

我理解理解,太难了,这个声明周期和协变抗变!

lan 2021-10-11 19:10

想了一下午,rust好难啊。贴一下我的理解,如有错误还请斧正。

这是编译不通过的情况(&mut bar):

#![feature(allocator_api)]
#![allow(unused)]
use std::alloc::{Allocator, Global};
struct  Foo<'a> {
    h: &'a mut Vec<usize, &'a Global>
}
fn _s() {
    let s = Global;
    { 
        // 期望的类型: Vec<usize, &'_ Global> 
        // 提供的类型: Vec<usize, &'scope_s Global>
        // Vec<T, A>对A协变,其中A也就是&'a Global对'a协变:
        // 型变后的类型: Vec<usize, &'scope_bar Global> (编译器总是尽可能缩小生命周期的范围)
        let mut bar = Vec::new_in(&s); 
        {
            let foo = Foo {
                // 期望的类型: &'a mut Vec<usize, &'a Global>
                // 提供的类型: &'scope_bar mut Vec<usize, &'scope_bar Global>
                // 因为&'a mut T对T不变(T=Vec<usize, &'scope_bar Global>),这里&'scope_bar Global中的'scope_bar不能"缩小"(编译器总是尽可能缩小生命周期的范围),
                // 尽管&'a mut T对'a协变,但'a已经确定是'scope_bar,不能改变了。
                // 型变后的类型: &'scope_bar mut Vec<usize, &'scope_bar Global> (没有变化)
                h: &mut bar, 
            };
            // 'scope_foo: drop: foo
        }
        // 'scope_bar: drop: bar, &'scope_bar mut bar, &'scope_bar s. 
        // 因为&mut bar和bar同时在这里drop,Allocator又没有被标记为#[may_dangle],所以DropCheck检查失败了。
    }
    // 'scope_s: drop: s. 
}

这是编译通过的情况(&bar

#![feature(allocator_api)]
#![allow(unused)]
use std::alloc::{Allocator, Global};
struct  Foo<'a> {
    h: &'a Vec<usize, &'a Global>
}
fn _s() {
    let s = Global;
    { 
        // 期望的类型: Vec<usize, &'_ Global> 
        // 提供的类型: Vec<usize, &'scope_s Global>
        // Vec<T, A>对A协变,其中A也就是&'a Global对'a协变:
        // 型变后的类型: Vec<usize, &'scope_bar Global> (编译器总是尽可能缩小生命周期的范围)
        let mut bar = Vec::new_in(&s); 
        {
            let foo = Foo {
                // 期望的类型: &'a mut Vec<usize, &'a Global>
                // 提供的类型: &'scope_bar mut Vec<usize, &'scope_bar Global>
                // &'a T同时对'a与T协变,其中的T也就是Vec<T, A>对A协变,其中的A也就是&'a Global又对&'a协变,
                // 那么编译器这里可以同时将两个'scope_bar在合理的范围内尽量缩小一些: 
                // 型变后的类型: &'scope_foo mut Vec<usize, &'scope_foo Global> (借用的生命周期缩短了)
                h: &bar, 
            };
            // 'scope_foo:drop: foo, &'scope_foo mut bar
        }
        // 'scope_bar: drop: bar, &'scope_bar s. 
    }
    // 'scope_s: drop: s. 
}

总的来说,不是【可变借用和不可变借用的drop顺序不一样】,而是型变和不恰当的生命周期标注导致DropCheck失败了。

DropCheck: https://doc.rust-lang.org/nomicon/dropck.html

型变: https://doc.rust-lang.org/nomicon/subtyping.html

Bai-Jinlin 2021-10-11 16:12

你用的应该是bumpalo,那写成这样就行了,你生命周期本来就写的有问题。

struct Foo<'a, 'bump: 'a> {
    h: &'a mut Vec<'bump, usize>,
}
1 共 3 条评论, 1 页