Borrow checking values into and out of struct fields?

So I got this tiny parser and I'm having some lovely time writing it. But I heard heap allocations are the devil (more or less), it might have been exaggerated for comic effect.

example.rs

pub struct Parse<'a, R> {
    slave: Lex<'a, R>
}

enum Transfer<'a> {
    Result(&'a str)
}

pub struct Lex <'a, R> {
    src:&'a R
}

impl<'a,R:Buffer> Lex<'a, R> {
    pub fn make(src : R) -> Lex<'a, R> {
        Lex {
            src: &'a src
        }
    }

    pub fn results(&mut self) -> Transfer<'a> {
        let line = match self.src.read_line() {
            Ok(line) => {
                line
            },
            _ => ~""
        };
        let brw = line.as_slice();
        Result(brw)
    }
}

fn main() {

}

Compilation fails with these errors:

example.rs:16:18: 16:25 error: `src` does not live long enough
example.rs:16             src: &'a src
                               ^~~~~~~
example.rs:14:40: 18:6 note: reference must be valid for the lifetime &'a  as defined on the block at 14:39...
example.rs:14     pub fn make(src : R) -> Lex<'a, R> {
example.rs:15         Lex {
example.rs:16             src: &'a src
example.rs:17         }
example.rs:18     }
example.rs:14:40: 18:6 note: ...but borrowed value is only valid for the block at 14:39
example.rs:14     pub fn make(src : R) -> Lex<'a, R> {
example.rs:15         Lex {
example.rs:16             src: &'a src
example.rs:17         }
example.rs:18     }
example.rs:21:26: 21:34 error: cannot borrow immutable dereference of `&`-pointer `*self.src` as mutable
example.rs:21         let line = match self.src.read_line() {
                                       ^~~~~~~~
example.rs:27:19: 27:23 error: `line` does not live long enough
example.rs:27         let brw = line.as_slice();
                                ^~~~
example.rs:20:47: 29:6 note: reference must be valid for the lifetime &'a  as defined on the block at 20:46...
example.rs:20     pub fn results(&mut self) -> Transfer<'a> {
example.rs:21         let line = match self.src.read_line() {
example.rs:22             Ok(line) => {
example.rs:23                 line
example.rs:24             },
example.rs:25             _ => ~""
              ...
example.rs:20:47: 29:6 note: ...but borrowed value is only valid for the block at 20:46
example.rs:20     pub fn results(&mut self) -> Transfer<'a> {
example.rs:21         let line = match self.src.read_line() {
example.rs:22             Ok(line) => {
example.rs:23                 line
example.rs:24             },
example.rs:25             _ => ~""
              ...

Using heap allocations via ~ is not the goal for me. I can already achieve that.

So is it possible using borrow checker to allow:

  1. A constructor to build Lex using a Buffer provided by Parse?
  2. Enum Transfer to borrow data extracted from Lex into Parse?

Answers


Lex.make: the problem is that you are taking an R by value. That is, you are consuming it. At the end of the function, it is freed. Therefore, a reference to it is not valid. What you need to do instead is take &'a R instead of R as the argument.

Lex.results: read_line() returns Result<~str, IoError>. Again, the object (this time a ~str) is owned inside the method, and so as soon as you get to the end of the method it will be freed as it passes out of scope. Thus, you can't use a reference—you should just pass the ~str back to the caller, no lifetime worry attached.

Here's the final code:

pub struct Parse<'a, R> {
    slave: Lex<'a, R>
}

enum Transfer {
    Result(~str)
}

pub struct Lex<'a, R> {
    src: &'a R
}

impl<'a, R: Buffer> Lex<'a, R> {
    pub fn make(src: &'a R) -> Lex<'a, R> {
        Lex {
            src: src
        }
    }

    pub fn results(&mut self) -> Transfer {
        let line = match self.src.read_line() {
            Ok(line) => line,
            _ => ~"",
        };
        Result(line)
    }
}

fn main() {
}

Need Your Help

MvvMCross bind command with parameter (in C# code)

binding parameters xamarin.ios command mvvmcross

How can I bind a command to a button in code in MvvMCross (Xamarin.iOS) with specifying a command parameter?

Yii and Knockout Together?

php javascript jquery yii knockout.js

I am trying to decide on a set of tools to use for a new web app I am going to build.