关于rust函数参数生命周期的疑问

struct AttributeState<'a>{
    keys: HashSet<&'a str>,
    values: HashSet<&'a str>,
    header_base_score: f64,
    value_base_score: f64,
}

impl<'a> AttributeState<'a>{
   
    pub(crate) fn contain_key(&self, entity: &str) -> bool{
        self.keys.contains(entity)
    }
    pub(crate) fn contains_value(&self, entity: &str) -> bool{
        self.values.contains(entity)
    }
    pub(crate) fn add_header(&'a mut self, entity: &'a str){
        self.keys.insert(entity);
    }
    pub(crate) fn add_value(&'a mut self, entity: &'a str){
        self.values.insert(entity);
    }
}
pub(crate) struct TableScoring {
    name: String,
    primary_key: String,
}

impl TableScoring {
    fn scoring(&self, candidate: &Vec<Token>) -> f64{
        let mut primary_mask = 0x0u8;
        // let mut  attribute_mask = 0x0u32;
        let mut attribute_state = AttributeState::new(1.0, 1.2);
        let mut cell_state = RefCell::new(attribute_state);
        let mut score = 0.0;
        for token in candidate{
            if token.is_primary(&self.primary_key){
                score += self.primary_scoring(token, &mut primary_mask);
            }else {
                let mut mut_state = cell_state.borrow_mut();
                score += self.attribute_scoring(token, &mut mut_state);
            }
        }
        score
    }
    fn primary_scoring(&self, token: &Token, mask: &mut u8) -> f64{
        unimplemented!()
    }
    fn attribute_scoring<'a>(&self, token: &'a Token, state: &'a mut RefMut<AttributeState<'a>>) -> f64
    {
        // do something, 将token.entity添加到state.keys和values
        // 逻辑上来说,token的生命周期应该更长,才能将token.entity的引用添加到state
        // 编译器却要求state的生命周期应该比token更长 attribute_scoring<'a, 'b: 'a>(&self, token: &'a Token, state: &'b mut RefMut<AttributeState<'a>>) 
       
        unimplemented!()
    }
}
// 对于return a或b的引用,return value的生命周期应该更短
// Here, Rust infers a lifetime that is as short as possible.
// The two references are then coerced to that lifetime.
fn multiply<'a>(first: &'a i32, second: &'a i32) -> i32 {
    first * second
}

// `<'a: 'b, 'b>` reads as lifetime `'a` is at least as long as `'b`.
// Here, we take in an `&'a i32` and return a `&'b i32` as a result of coercion.
fn choose_first<'a: 'b, 'b>(first: &'a i32, _: &'b i32) -> &'b i32 {
    first
}

fn main() {
    let first = 2; // Longer lifetime
    
    {
        let second = 3; // Shorter lifetime
        
        println!("The product is {}", multiply(&first, &second));
        println!("{} is the first", choose_first(&first, &second));
    };
}

但是对于改变可变形参的情况,看编译器的报错,mut_state是局部变量,无法满足借用检查,似乎只能将state中的Keys和Values的Item改成String才可以。为什么?

4 个赞

不懂 顶一下

image

The Slice Type
Slices let you reference a contiguous sequence of elements in a collection rather than the whole collection. A slice is a kind of reference, so it does not have ownership.

这个原因 A slice is a kind of reference, so it does not have ownership.

String 拥有自己完整的生命周期,将 keysvaluesHashSet<&'a str> 改为 HashSet<String> 之后,这些字段就拥有了它们包含的数据的所有权

https://doc.rust-lang.org/book/ch04-03-slices.html

1 个赞

这里把self的生命周期约束去掉
改为

impl<'a> AttributeState<'a> {
    pub(crate) fn contain_key(&self, entity: &str) -> bool {
        self.keys.contains(entity)
    }
    pub(crate) fn contains_value(&self, entity: &str) -> bool {
        self.values.contains(entity)
    }
    pub(crate) fn add_header(&mut self, entity: &'a str) {
        self.keys.insert(entity);
    }
    pub(crate) fn add_value(&mut self, entity: &'a str) {
        self.values.insert(entity);
    }
}

还有

    fn attribute_scoring<'a>(
        &self,
        token: &'a Token,
        state: &mut RefMut<AttributeState<'a>>,
    ) -> f64 {
        // do something, 将token.entity添加到state.keys和values
        // 逻辑上来说,token的生命周期应该更长,才能将token.entity的引用添加到state
        // 编译器却要求state的生命周期应该比token更长 attribute_scoring<'a, 'b: 'a>(&self, token: &'a Token, state: &'b mut RefMut<AttributeState<'a>>)
        state.keys.insert(token.entity);
        todo!()
    }

很少需要对可变借用本身进行生命周期约束

2 个赞

调用 borrow_mut()时,你得到了一个预期为短生命周期的可变借用,但是你的方法却使用 &'a mut self 让这个短生命周期的可变借用“延长”到了 'a ,这比从 borrow_mut() 获得的借用时间更长。

self 的可变借用只存在方法调用期间,而不是整个 'a 生命周期,因此我们不需要对 self 的可变引用作生命周期约束,而对 entity: &'a str 的生命周期约束已经表明entity至少和self本身的 HashSet存储的生命周期一样长。

1 个赞

你的理解是对的,正常情况下 attribute_scoring 函数中 state 的生命周期是要大于 token 才行。但如果你在 attribute_scoring 里调用了 add_headeradd_value 编译器就会告诉你相反的结果。
楼上已经给出答案了,是你这俩 add 函数的生命周期标注的太严格了。

3 个赞

非常感谢,我想你是对的,我等会试试?state的方法add_header中&mut self添加了预期之外的生命周期标注,我没注意到这点。

简单跑了一下测试,确实是&'a mut self的标注导致的。非常感谢

1 个赞