< 返回版块

sin 发表于 2023-08-07 16:05

Tags:生命周期

如下代码,在初始化的时候,我需要往a中加入部分元素,然后把a中部分元素的引用放入b中,这里的生命周期似乎标注不了。 谢谢各位大佬


struct Container
{
    a: Vec<i32>,
    b:Vec<&'a i32>,
}

评论区

写评论
pama 2023-08-10 11:32

那你为啥不存下标呢?

araraloren 2023-08-08 10:59

那你为啥不存下标呢?

github.com/shanliu/lsys 2023-08-07 20:11

https://rustcc.cn/article?id=b55eca8f-82ce-45c4-b902-c1c0059727aa

等下 苦瓜小仔 被你逼疯。

wangbyby 2023-08-07 19:20

等于说这里有自引用。 如果可以确保a初始化后就不会更改,搜集元素下标也是可行的。

struct A{
  a: Vec<i32>,
  index: Vec<usize>,
}

如果是指针版本就类似这种:

struct APointer{
  a: Vec<i32>,
  pointers: Vec<*const i32>
}

区别就只是相对寻址和绝对寻址。

Wuyan 2023-08-07 18:34

使用'static生命周期是多余的,可使用下面方式:

struct Container<'a>
{
    a: Vec<i32>,
    b:Vec<&'a i32>,
}
impl<'a> Container<'a> {
    fn new(data:Vec<i32>)->Self{
        let mut c=Self{
            a: data,
            b: vec![],
        };
        unsafe{
            let l=c.a.len();
            for i in 3..l{
                //通过引用转指针再转引用可将生命周期转为'static,这样就可赋值给任何生命周期引用了
                let temp=& *((&c.a[i]) as *const i32);
                c.b.push(temp);
            }
        }
        c
    }
}

--
👇
sin: 大佬,谢谢,你发的这个我学到了。

作者 sin 2023-08-07 18:23

不过你写的这个确实对我这种新手学习rust有很大帮助,十分感激。

--
👇
byeblack: ``` fn main() { // 无法更改a的值, 所以你每次都需要重新初始化 let z = (1..10).collect::<Vec>(); let mut x = Solution1 { a: z, b: vec![] }; x.a.iter().for_each(|i| { if i % 2 == 0 { x.b.push(i) } }); println!("{:?}", x); // x.a[0] = 10; // cannot borrow x.a as mutable because it is also borrowed as immutable

// 使用下标访问,但每次都需要检查下标是否越界,以免发生意外,而且一旦a的长度发生变化,下标就可能失效,需要重建下标
let z = (1..10).collect::<Vec<i32>>();
// 一步到位??
let mut x = Solution2::new(z);
x.build_index();
println!("a: {:?}, b为下标{:?}", x.a, x.b);

// 修改某个值
if let Some(v) = x.a.get_mut(x.b[0]) {
    *v = 10;
} else {
    panic!("下标越界")
}

// 增加值
x.a.extend([1, 2, 3].iter());
x.build_index();
println!("增加值 a: {:?}, b为下标{:?}", x.a, x.b);

// 连续读取值
println!("连续读取值 {:?}", x.get_all());

}

#[derive(Debug)] struct Solution1<'a> { a: Vec, b: Vec<&'a i32>, }

#[derive(Debug)] struct Solution2 { a: Vec, b: Vec, }

impl Solution2 { // 初始化 fn new(value: Vec) -> Self { let mut x = Solution2 { a: value, b: vec![], }; x.build_index(); x }

// 重建下标
fn build_index(&mut self) {
    self.b = vec![];
    self.a.iter().enumerate().for_each(|(index, value)| {
        if value % 2 == 0 {
            self.b.push(index)
        }
    });
}

// 读取下标对应的值
fn get_all(&self) -> Vec<&i32> {
    self.a
        .iter()
        .enumerate()
        .filter(|(index, _value)| self.b.contains(index))
        .map(|(_index, value)| value)
        .collect::<Vec<_>>()
}

}


--  
👇  
aj3n: 如果你原始问题就是需要保存一个i32的引用,我想提出这是没有意义的,不如直接解引用复制;
否则建议直接保存下标;

作者 sin 2023-08-07 18:17

哈哈,大佬,你写的很棒,但是似乎不够rusty[旺柴]

--
👇
byeblack: ``` fn main() { // 无法更改a的值, 所以你每次都需要重新初始化 let z = (1..10).collect::<Vec>(); let mut x = Solution1 { a: z, b: vec![] }; x.a.iter().for_each(|i| { if i % 2 == 0 { x.b.push(i) } }); println!("{:?}", x); // x.a[0] = 10; // cannot borrow x.a as mutable because it is also borrowed as immutable

// 使用下标访问,但每次都需要检查下标是否越界,以免发生意外,而且一旦a的长度发生变化,下标就可能失效,需要重建下标
let z = (1..10).collect::<Vec<i32>>();
// 一步到位??
let mut x = Solution2::new(z);
x.build_index();
println!("a: {:?}, b为下标{:?}", x.a, x.b);

// 修改某个值
if let Some(v) = x.a.get_mut(x.b[0]) {
    *v = 10;
} else {
    panic!("下标越界")
}

// 增加值
x.a.extend([1, 2, 3].iter());
x.build_index();
println!("增加值 a: {:?}, b为下标{:?}", x.a, x.b);

// 连续读取值
println!("连续读取值 {:?}", x.get_all());

}

#[derive(Debug)] struct Solution1<'a> { a: Vec, b: Vec<&'a i32>, }

#[derive(Debug)] struct Solution2 { a: Vec, b: Vec, }

impl Solution2 { // 初始化 fn new(value: Vec) -> Self { let mut x = Solution2 { a: value, b: vec![], }; x.build_index(); x }

// 重建下标
fn build_index(&mut self) {
    self.b = vec![];
    self.a.iter().enumerate().for_each(|(index, value)| {
        if value % 2 == 0 {
            self.b.push(index)
        }
    });
}

// 读取下标对应的值
fn get_all(&self) -> Vec<&i32> {
    self.a
        .iter()
        .enumerate()
        .filter(|(index, _value)| self.b.contains(index))
        .map(|(_index, value)| value)
        .collect::<Vec<_>>()
}

}


--  
👇  
aj3n: 如果你原始问题就是需要保存一个i32的引用,我想提出这是没有意义的,不如直接解引用复制;
否则建议直接保存下标;

作者 sin 2023-08-07 18:15

感谢大佬点播,我发现确实需要Pin住,我去学习一下这方面的知识。

--
👇
zylthinking: 不过这可能没有什么意义, 因为 vec 可能会内存重分配, 因此引用还是会失效, 而且 'a 同于 Container liveness scope, 只读引用还好, b: Vec<&'a mut i32> 就不好办了

--
👇
zylthinking: ``` struct Container<'a> { a: Vec, b: Vec<&'a i32>, }

不过确实却要 Pin 住

byeblack 2023-08-07 18:10
fn main() {
    // 无法更改a的值, 所以你每次都需要重新初始化
    let z = (1..10).collect::<Vec<i32>>();
    let mut x = Solution1 { a: z, b: vec![] };
    x.a.iter().for_each(|i| {
        if i % 2 == 0 {
            x.b.push(i)
        }
    });
    println!("{:?}", x);
    // x.a[0] = 10; // cannot borrow `x.a` as mutable because it is also borrowed as immutable

    // 使用下标访问,但每次都需要检查下标是否越界,以免发生意外,而且一旦a的长度发生变化,下标就可能失效,需要重建下标
    let z = (1..10).collect::<Vec<i32>>();
    // 一步到位??
    let mut x = Solution2::new(z);
    x.build_index();
    println!("a: {:?}, b为下标{:?}", x.a, x.b);

    // 修改某个值
    if let Some(v) = x.a.get_mut(x.b[0]) {
        *v = 10;
    } else {
        panic!("下标越界")
    }

    // 增加值
    x.a.extend([1, 2, 3].iter());
    x.build_index();
    println!("增加值 a: {:?}, b为下标{:?}", x.a, x.b);

    // 连续读取值
    println!("连续读取值 {:?}", x.get_all());
}

#[derive(Debug)]
struct Solution1<'a> {
    a: Vec<i32>,
    b: Vec<&'a i32>,
}

#[derive(Debug)]
struct Solution2 {
    a: Vec<i32>,
    b: Vec<usize>,
}

impl Solution2 {
    // 初始化
    fn new(value: Vec<i32>) -> Self {
        let mut x = Solution2 {
            a: value,
            b: vec![],
        };
        x.build_index();
        x
    }

    // 重建下标
    fn build_index(&mut self) {
        self.b = vec![];
        self.a.iter().enumerate().for_each(|(index, value)| {
            if value % 2 == 0 {
                self.b.push(index)
            }
        });
    }

    // 读取下标对应的值
    fn get_all(&self) -> Vec<&i32> {
        self.a
            .iter()
            .enumerate()
            .filter(|(index, _value)| self.b.contains(index))
            .map(|(_index, value)| value)
            .collect::<Vec<_>>()
    }
}

--
👇
aj3n: 如果你原始问题就是需要保存一个i32的引用,我想提出这是没有意义的,不如直接解引用复制; 否则建议直接保存下标;

作者 sin 2023-08-07 18:02

大概的代码是这样的,我想把container的初始化封装到new中,但是编译器提示我不能这样借用。

pub struct container<'a> {
        tree: TreeSet,
        group: GroupSet<'a>,
    }

 impl<'a> container<'a> {
   pub fn new()->Self
   {
      let tree = build_tree();
      let group = build_group(&tree);
      Self{ tree, group}
    }
}


作者 sin 2023-08-07 17:55

我很确定的是a第一次初始化以后不会再修改了,这里的A和B是两个结构体,我先对A结构体初始化以后,对B结构体初始化需要保存A的引用,我想知道的是有没有什么办法来让他们一次完成初始化。

--
👇
zylthinking: 不过这可能没有什么意义, 因为 vec 可能会内存重分配, 因此引用还是会失效, 而且 'a 同于 Container liveness scope, 只读引用还好, b: Vec<&'a mut i32> 就不好办了

--
👇
zylthinking: ``` struct Container<'a> { a: Vec, b: Vec<&'a i32>, }

不过确实却要 Pin 住

作者 sin 2023-08-07 17:53

大佬,谢谢,你发的这个我学到了。

👇
Wuyan: 如果你能处理好a移动后b做对应更改的话,不知道下面这样是否满足你的要求:

struct Container
{
    a: Vec<i32>,
    b:Vec<&'static mut i32>,
}
impl Container {
    fn new(data:Vec<i32>)->Self{
        let mut c=Self{
            a: data,
            b: vec![],
        };
        unsafe{
            let l=c.a.len();
            for i in 3..l{
                let temp=(&c.a[i]) as *const i32 as *mut i32;
                // 转化生命周期为'static
                let b=Box::leak(Box::from_raw(temp));
                c.b.push(b);
            }
        }
        c
    }
}

a容量改变时,要注意重新分配内存导致b可能失效问题(需要重新设置b),如果你呢 ba连续内存的引用也可采用下面的方式:

struct Container
{
    a: Vec<i32>,
    b:&'static [i32],
}
impl Container {
    fn new(data:Vec<i32>)->Self{
        let l=data.len();
            
        let ptr=data.as_ptr();
        
        let b=unsafe { std::slice::from_raw_parts(ptr.add(3), l-3) };
        Self{
            a: data,
            b: b,
        }
    }
}
作者 sin 2023-08-07 17:53

--
👇
byeblack: 这种?

大佬,你发的这个是先把空向量赋给b,然后往b里面添加,我想问的是有没有什么办法在初始化的时候一步到位。

Wuyan 2023-08-07 17:16

如果你能处理好a移动后b做对应更改的话,不知道下面这样是否满足你的要求:

struct Container
{
    a: Vec<i32>,
    b:Vec<&'static mut i32>,
}
impl Container {
    fn new(data:Vec<i32>)->Self{
        let mut c=Self{
            a: data,
            b: vec![],
        };
        unsafe{
            let l=c.a.len();
            for i in 3..l{
                let temp=(&c.a[i]) as *const i32 as *mut i32;
                // 转化生命周期为'static
                let b=Box::leak(Box::from_raw(temp));
                c.b.push(b);
            }
        }
        c
    }
}

a容量改变时,要注意重新分配内存导致b可能失效问题(需要重新设置b),如果你呢 ba连续内存的引用也可采用下面的方式:

struct Container
{
    a: Vec<i32>,
    b:&'static [i32],
}
impl Container {
    fn new(data:Vec<i32>)->Self{
        let l=data.len();
            
        let ptr=data.as_ptr();
        
        let b=unsafe { std::slice::from_raw_parts(ptr.add(3), l-3) };
        Self{
            a: data,
            b: b,
        }
    }
}
zylthinking 2023-08-07 17:15

不过这可能没有什么意义, 因为 vec 可能会内存重分配, 因此引用还是会失效, 而且 'a 同于 Container liveness scope, 只读引用还好, b: Vec<&'a mut i32> 就不好办了

--
👇
zylthinking: ``` struct Container<'a> { a: Vec, b: Vec<&'a i32>, }

不过确实却要 Pin 住
liming01 2023-08-07 17:13

这里有介绍

https://quinedot.github.io/rust-learning/pf-meta.html#avoid-self-referential-structs

aj3n 2023-08-07 17:12

如果你原始问题就是需要保存一个i32的引用,我想提出这是没有意义的,不如直接解引用复制; 否则建议直接保存下标;

byeblack 2023-08-07 16:58
zylthinking 2023-08-07 16:50
struct Container<'a>
{
    a: Vec<i32>,
    b:Vec<&'a i32>,
}

不过确实却要 Pin 住

ruby 2023-08-07 16:30

这种属于自引用生命周期难搞,这种应用场景应该用 Rc 或者 Arc 引用计数合适点

1 共 20 条评论, 1 页