0

As a Rust newbie, I'm having a really hard time understanding what appear to be these most significant features. I have read the relevant sections TRPL (1 and 2) multiple times, and yet I still can't get my code to compile. As an example, I've extracted and simplified part of a bigger project.

This example program builds a list of strings (I've used Vec), either from the command line arguments, or, if the -c parameter is given, from the clipboard.

extern crate clipboard;
use clipboard::{ClipboardContext, ClipboardProvider};

extern crate clap;
use clap::{App, Arg, ArgMatches};

#[allow(unused)] // Reduce noise in compiler output
fn main() {
    let cmdl: ArgMatches = App::new("mwe")
        .arg(
            Arg::with_name("clipboard")
                .short("c")
                .conflicts_with("list")
                .takes_value(false),
        )
        .arg(
            Arg::with_name("list")
                .takes_value(true)
                .required_unless("clipboard")
                .multiple(true),
        )
        .get_matches();
    println!("{:?}", cmdl);

    let vlist: Vec<&str> = Vec::new();
    if cmdl.is_present("clipboard") {
        let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
        let vlist = ctx.get_contents()
            .unwrap()
            .split_whitespace()
            .collect::<Vec<_>>();
    } else {
        let vlist = cmdl.values_of("list").unwrap().collect::<Vec<_>>();
    };
    println!("{:?}", vlist);
}

On compiling, this is the output:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:28:25
   |
28 |               let vlist = ctx.get_contents()
   |  _________________________^
29 | |                 .unwrap()
   | |_________________________^ temporary value does not live long enough
30 |                   .split_whitespace()
31 |                   .collect::<Vec<_>>();
   |                                       - temporary value dropped here while still borrowed
32 |           } else {
   |           - temporary value needs to live until here
   |
   = note: consider using a `let` binding to increase its lifetime

Now, I have (at least) two problems:

  1. I just don't understand why what I've written is in error. It may be that I'm just a slow learner, or, maybe, that to perceive some aspects of borrowing and lifetimes one has to have a more intimate understanding of the libraries one is using. Please explain what's going on here?
  2. I have no idea of the best and/or most efficient way to fix this; please guide me.

As a footnote, these "no-more-garbage-collection" features are one of the things that attract me to Rust. But I can't help thinking, occasionally, that the examples in TRPL need to be simpler, and that the learning curve in this area looks more like a precipice. All help and illumination greatly appreciated.


Ongoing evolution of the problem

Following https://stackoverflow.com/a/37265024/9634 this answer to “borrowed value does not live long enough” seems to blame the wrong thing (which gave me a better understanding of the library internals), I amended my code, replacing

    let vlist = ctx.get_contents()
        .unwrap()
        .split_whitespace()
        .collect::<Vec<_>>();

by

for item in ctx.get_contents().unwrap().split_whitespace() {
    vlist.push(&item.to_string()) ;
} 

The error has now moved a little:

error[E0597]: borrowed value does not live long enough
  --> src\main.rs:24:25
   |
24 |             vlist.push(&item.to_string()) ;
   |                         ^^^^^^^^^^^^^^^^  - temporary value dropped here while still borrowed
   |                         |
   |                         temporary value does not live long enough
...
32 | }
   | - temporary value needs to live until here
   |
   = note: consider using a `let` binding to increase its lifetime

I'd like very much to follow the recommendation of "using a let binding to increase its lifetime" (as reinforced in the comments), but I haven't a clue what this would look like. Please help.

Brent.Longborough
  • 9,567
  • 10
  • 42
  • 62
  • 1
    Could you please [edit] your question to explain why the answers for [Using a `let` binding to increase value lifetime](https://stackoverflow.com/q/26080157/155423) or [“borrowed value does not live long enough” seems to blame the wrong thing](https://stackoverflow.com/q/37264396/155423) do not answer this question? – Shepmaster Mar 27 '18 at 13:35
  • 3
    *the best and/or most efficient way to fix this* — Have you tried applying the suggestion from the compiler: "consider using a `let` binding to increase its lifetime" – Shepmaster Mar 27 '18 at 13:38
  • Strange that googling the error message only gives [this answer](https://users.rust-lang.org/t/borrowed-value-does-not-live-long-enough/7225) but nothing on SO. – MB-F Mar 27 '18 at 13:39
  • @Shepmaster : Oh, yes; that led me deep and unsuccessfully into Alice's Wonderland, and returning to my base code to ask for help seemed like a better idea I think the clue from your answer to "seems to blame the wrong thing" will help, though, and I'll update or delete the question in an hour or so. – Brent.Longborough Mar 27 '18 at 13:45
  • 1
    No need to *delete* the question if it's solved by an existing one. You can vote to close your own question as a duplicate, which helps everyone else who stumbles across this question from search in the future. – Shepmaster Mar 27 '18 at 13:54
  • @Shepmaster Yes, of course. – Brent.Longborough Mar 27 '18 at 13:58
  • @Shepmaster, just out of curiosity, what's the "borrowed value" in this specific case? `ctx.get_contents` is a `Result>` according to [the docs](https://docs.rs/clipboard/0.4.6/clipboard/x11_clipboard/struct.X11ClipboardContext.html) (so it's not borrowing from `ctx`), and at the end of the block the string is collected into a new vector. I'm not even sure if *I* see what the compiler is unhappy with. – MutantOctopus Mar 27 '18 at 14:00
  • 1
    @BHustus the `Result` is unwrapped yielding `String`, then `split_whitespace` takes references to the `String`, then the `String` is dropped. The `String` is borrowed by `Split`. `String::new().split_whitespace().collect::>()` is a MCVE. – Shepmaster Mar 27 '18 at 14:09
  • 1
    Brent, in your new edit, `&item.to_string()` creates a `String`, then makes a reference to it (as if you did `&( item.to_string() )`), which is pushed into a collection outside of the block - which is bad. Try just `item.to_string()`, which creates an owned object that hopefully shouldn't raise that error, and create a `Vec` instead. – MutantOctopus Mar 27 '18 at 14:18
  • @BHustus That gives me `expected &str, found struct 'std::string::String' help: consider borrowing here: '&item.to_string()'`. Do I need Vec rather than Vec<&str>? -- Yep, Vec compiled! Thank you. – Brent.Longborough Mar 27 '18 at 14:24

0 Answers0