rust - How to tell the compiler a lifetime is no longer valid? - Stack Overflow

While I understand why the compiler doesn't like the last statement in this code:struct Person<

While I understand why the compiler doesn't like the last statement in this code:


struct Person<'a> {
    name: &'a str,
}
impl<'a> Person<'a> {
    pub fn replace_name(&mut self, newname: &'a str) {
        self.name = newname;
    }
}

#[test]
fn test_person() {
    let firstname = "John".to_string();
    let mut p = Person { name: &firstname };
    assert_eq!(p.name, "John");

    {
        let newname = "Bob".to_string();
        p.replace_name(&newname);
        assert_eq!(p.name, "Bob");
        p.replace_name(&firstname);
    }
    // This will fail because the lifetime of newname is shorter than p:
    //assert_eq!(p.name, "John");
}

How can I tell it that it's OK because I replaced the newname with firstname?

While I understand why the compiler doesn't like the last statement in this code:


struct Person<'a> {
    name: &'a str,
}
impl<'a> Person<'a> {
    pub fn replace_name(&mut self, newname: &'a str) {
        self.name = newname;
    }
}

#[test]
fn test_person() {
    let firstname = "John".to_string();
    let mut p = Person { name: &firstname };
    assert_eq!(p.name, "John");

    {
        let newname = "Bob".to_string();
        p.replace_name(&newname);
        assert_eq!(p.name, "Bob");
        p.replace_name(&firstname);
    }
    // This will fail because the lifetime of newname is shorter than p:
    //assert_eq!(p.name, "John");
}

How can I tell it that it's OK because I replaced the newname with firstname?

Share Improve this question asked Mar 2 at 21:34 jejejeje 3,2213 gold badges28 silver badges42 bronze badges 3
  • 5 Allowing that might not be sound. After all, replace_name() could contain if rng.gen::<bool>() { self.name = newname }. In other words, given the signature of replace_name(), there is no guarantee that it's safe to lengthen the lifetime to that of firstname. For this to work, replace_name() should consume self and return one with a new lifetime: play.rust-lang./… – user4815162342 Commented Mar 2 at 21:45
  • An alternative to what @user4815162342 suggested is a callback-style API, that takes a callback and restores the value after calling it (the actual implementation will be done using unsafe). – Chayim Friedman Commented Mar 2 at 22:15
  • 1 The lifetime is on the type, not the function! From the compiler's point of view, there is no guarantee that the function would replace the value—maybe the function pushes values into a vector; the function's name has no meaning for the compiler. – Raeisi Commented Mar 3 at 7:18
Add a comment  | 

1 Answer 1

Reset to default 1

The way to solve this for the code you're actually showing is to copy or borrow Person to make a new local Person with a shorter lifetime:

impl Person<'_> {
    pub fn shorten(&self) -> Person<'_> {
        Person { name: self.name }
    }
}


let firstname = "John".to_string();
let mut person = Person { name: &firstname };
assert_eq!(person.name, "John");

{
    let newname = "Bob".to_string();
    let mut new_person = person.shorten();
    new_person.replace_name(&newname);
}

assert_eq!(person.name, "John");

This doesn't mutate the original person, but instead creates a different person that borrows the original one that can be mutated with local data. At the end of the {} local scope, the new person is dropped, and the old person still exists, with the old data and longer lifetime.

I don't know for sure if this solves whatever actual use-case you have, but for the sample code you've posted it neatly resolves this issue.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745117601a4612222.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信