最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

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

programmeradmin1浏览0评论

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.

发布评论

评论列表(0)

  1. 暂无评论