0

I am trying to parse JSON line-by-line from stdin using the pom library.

I've stolen the json implementation provided on the homepage (and have omitted that code below; it's not relevant), and am getting a borrow error from the following code:

fn main() {
    for line in io::stdin().lock().lines() {
        let line2 = line.unwrap().as_bytes();
        let _value = json().parse(line2).unwrap();
    }
}

The error:

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:73:23
   |
73 |         let tmpline = line.unwrap().as_bytes();
   |                       ^^^^^^^^^^^^^------------ temporary value is freed at the end of this statement
   |                       |
   |                       creates a temporary which is freed while still in use
   |                       argument requires that borrow lasts for `'static`

.parse in the pom libray has the type:

pub fn parse(&self, input: &'a [I]) -> Result<O>

.as_bytes() has the type:

pub fn as_bytes(&self) -> &[u8]

Obviously, I'm borrowing incorrectly here, but I'm not entirely sure how to fix this.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
chrisdotcode
  • 1,569
  • 2
  • 17
  • 22

2 Answers2

1

The problem here is that you're using a reference to a value whose lifetime is shorter than you need, and lies in this line: line.unwrap().as_bytes().

as_bytes() returns a reference to the underlying slice of u8s. Now, that underlying slice, returned by unwrap(), happens to be a temporary which will die at the end of the statement.

In Rust, you can re-declare variables with the same name in the current scope and they will shadow the one(s) previously defined. To fix the problem, store the value somewhere, and then get a reference to it. Like so:

fn main() {
    for line in io::stdin().lock().lines() {
        let line = line.unwrap();
        let bytes = line.as_bytes();
        let _value = json().parse(bytes).unwrap();
    }
}

Now the value returned by as_bytes() can point to something that lives as long as the current scope. Previously, instead, you had this:

fn main() {
    for line in io::stdin().lock().lines() {
        let line2 = line.unwrap().as_bytes(); // <-- the value returned by unwrap dies here
        let _value = json().parse(line2).unwrap(); // <-- line2 would be dangling here
    }
}
brainplot
  • 131
  • 2
  • 12
  • Using your code, I get `line does not live long enough; .borrowed value does not live long enough; argument requires that line is borrowed for 'static` on the `let bytes = line.as_bytes()` line. Maybe it has something to do with the function signature of what `json().parse()` expects? – chrisdotcode May 09 '19 at 18:12
0

line.unwrap() returns a String, which you then borrow from with as_bytes(). Since you never bind the String itself, only the borrowed byte slice, the String is dropped at the end of the statement, and the borrowed byte slice is invalidated.

Bind the temporary String to a variable with let s = line.unwrap(), then pass s.as_bytes() to json().parse.

ecstaticm0rse
  • 1,436
  • 9
  • 17
  • Unfortunately, that didn't work either. I get`borrowed value does not live long enough`. – chrisdotcode May 09 '19 at 18:03
  • 1
    This is separate issue which occurs `json()` is returning a `Parser<'static, ...>` when you need your parser to be variant over lifetimes. The [example code](https://github.com/J-F-Liu/pom/blob/master/examples/json.rs) returns such a `Parser`. You'll need to change your `json()` function to be generic over a lifetime as well. – ecstaticm0rse May 10 '19 at 19:18