2

I want move one struct into another and get references on parts of first struct as parts of other without cloning or copying, if it is possible. How to do it in right way?

fn main() {
    let foo = Foo::new();
    let bar = Bar::new(foo);
    println!("{:?}", bar);
}

#[derive(Debug)]
struct Foo {
    v: String,
}

impl Foo {
    pub fn new() -> Self {
        Foo {
            v: String::from("a|b"),
        }
    }

    pub fn get_a(&self) -> &str {
        &self.v[0..1]
    }

    pub fn get_b(&self) -> &str {
        &self.v[2..3]
    }
}

#[derive(Debug)]
struct Bar<'a> {
    foo: Foo,
    a: &'a str,
    b: &'a str,
}

impl<'a> Bar<'a> {
    pub fn new(f: Foo) -> Self {
        Bar::parse(f)
    }

    fn parse(f: Foo) -> Self {
        let a = f.get_a();
        let b = f.get_b();

        Bar { foo: f, a, b }
    }
}

Rust Playground

I got an error:

error[E0515]: cannot return value referencing function parameter `f`
  --> src/main.rs:44:9
   |
41 |         let a = f.get_a();
   |                 - `f` is borrowed here
...
44 |         Bar { foo: f, a, b }
   |         ^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function

error[E0515]: cannot return value referencing function parameter `f`
  --> src/main.rs:44:9
   |
42 |         let b = f.get_b();
   |                 - `f` is borrowed here
43 | 
44 |         Bar { foo: f, a, b }
   |         ^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function

error[E0505]: cannot move out of `f` because it is borrowed
  --> src/main.rs:44:20
   |
35 | impl<'a> Bar<'a> {
   |      -- lifetime `'a` defined here
...
41 |         let a = f.get_a();
   |                 - borrow of `f` occurs here
...
44 |         Bar { foo: f, a, b }
   |         -----------^--------
   |         |          |
   |         |          move out of `f` occurs here
   |         returning this value requires that `f` is borrowed for `'a`
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Barlog
  • 180
  • 2
  • 9

1 Answers1

1

The lifetime of the argument f to parse ends when parse returns. Older Rust compiler versions returned an error message which might have been more useful:

error[E0597]: `f` does not live long enough
  --> t.rs:41:17
   |
41 |         let a = f.get_a();
   |                 ^ borrowed value does not live long enough
...
45 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 35:1...
  --> t.rs:35:1
   |
35 | / impl<'a> Bar<'a> {
36 | |     pub fn new(f: Foo) -> Self {
37 | |         Bar::parse(f)
38 | |     }
...  |
45 | |     }
46 | | }
   | |_^

I can get your example to compile by changing the definition of Bar to:

#[derive(Debug)]
struct Bar<'a> {
    foo: &'a Foo,
    a: &'a str,
    b: &'a str,
}

and passing references of type &'a Foo to Bar::new and Bar::parse. However, it is unclear if this solution will work for your original problem. Maybe you need to use Rc if the ownership structure is too complicated.

Florian Weimer
  • 32,022
  • 3
  • 48
  • 92