Reputation: 18109
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:
Lex
using a Buffer
provided by Parse
? Transfer
to borrow data extracted from Lex
into Parse
?Upvotes: 0
Views: 85
Reputation: 90832
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() {
}
Upvotes: 2