9

I have a very simple method. The first argument takes in vector components ("A", 5, 0) and I will compare this to every element of another vector to see if they have the same ( _ , 5 , _) and then print out the found element's string.

Comparing ("A", 5, 0 ) and ("Q", 5, 2) should print out Q.

fn is_same_space(x: &str, y1: i32, p: i32, vector: &Vec<(&str, i32, i32)>) -> (&str) {
    let mut foundString = "";

    for i in 0..vector.len() {

        if y1 == vector[i].1 {
            foundString = vector[i].0;
        }

    }
    foundString    
}

However, I get this error

error[E0106]: missing lifetime specifier
 --> src/main.rs:1:80
  |
1 | fn is_same_space(x: &str, y1: i32, p: i32, vector: &Vec<(&str, i32, i32)>) -> (&str) {
  |                                                                                ^ expected lifetime parameter
  |
  = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or one of `vector`'s 2 elided lifetimes
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
boss revs
  • 331
  • 2
  • 4
  • 13
  • 3
    The point here is that you're returning an `&str` that's owned by *someone*. The compiler wants an idea of who that someone is, so it can know how long the memory that you `&str` points to is expected to live. You need to tell the compiler "the `&str` I'm returning will live as long as the references that are passed in" – turbulencetoo Apr 10 '17 at 18:46

2 Answers2

10

By specifying a lifetime:

fn is_same_space<'a>(x: &'a str, y1: i32, p: i32, vector: &'a Vec<(&'a str, i32, i32)>) -> (&'a str)

This is only one of many possible interpretations of what you might have meant for the function to do, and as such it's a very conservative choice - it uses a unified lifetime of all the referenced parameters.

Perhaps you wanted to return a string that lives as long as x or as long as vector or as long as the strings inside vector; all of those are potentially valid.


I strongly recommend that you go back and re-read The Rust Programming Language. It's free, and aimed at beginners to Rust, and it covers all the things that make Rust unique and are new to programmers. Many people have spent a lot of time on this book and it answers many beginner questions such as this one.

Specifically, you should read the chapters on:

There's even a second edition in the works, with chapters like:


For fun, I'd rewrite your code using iterators:

fn is_same_space<'a>(y1: i32, vector: &[(&'a str, i32, i32)]) -> &'a str {
    vector.iter()
        .rev() // start from the end
        .filter(|item| item.1 == y1) // element that matches
        .map(|item| item.0) // first element of the tuple
        .next() // take the first (from the end)
        .unwrap_or("") // Use a default value
}
Community
  • 1
  • 1
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Ah thank you kind sir. I know i should read the book but I'm more of a do code first, ask questions later type of guy. As you can see, my type inference is procrastination. I know it's very bad practice and should fix my habits. Thanks – boss revs Apr 10 '17 at 19:13
  • @bossrevs: I know the feeling; when I see a programming language "book" starting with pages upon pages of *syntax*, I feel like I need to throw up. It's boring, uninteresting, and I'll pick this stuff up naturally as I go. The new [Rust Book, 2nd edition](http://rust-lang.github.io/book/second-edition/index.html) is different though; it's very much a hands-on experience, with examples as you go. I really recommend checking it out, at least until the ownership/borrowing chapter (2nd meaty chapter). – Matthieu M. Apr 11 '17 at 11:04
  • The notion that just reading the book is going to make people understand some of these Rusty things is false. While it's helpful, sometimes understanding only comes over time having used these things. – JohnAllen Feb 19 '23 at 14:39
3

So the problem comes from the fact that vector has two inferred lifetimes, one for vector itself (the &Vec part) and one for the &str inside the vector. You also have an inferred lifetime on x, but that really inconsequential.

To fix it, just specify that the returned &str lives as long as the &str in the vector:

fn is_same_space<'a>(                        // Must declare the lifetime here
    x: &str,                                 // This borrow doesn't have to be related (x isn't even used)
    y1: i32,                                 // Not borrowed
    p: i32,                                  // Not borrowed or used
    vector: &'a Vec<(&'a str, i32, i32)>     // Vector and some of its data are borrowed here
) -> &'a str {                               // This tells rustc how long the return value should live
    ...
}
bheklilr
  • 53,530
  • 6
  • 107
  • 163
  • 1
    `&Vec<(&'a str, i32, i32)>` (or better, `&[(&'a str, i32, i32)]`, see http://stackoverflow.com/q/40006219/155423) should be enough. The lifetime of the container is inconsequential. – Shepmaster Apr 10 '17 at 19:28
  • @Shepmaster Thanks for the suggestion, I hadn't thought of using a slice instead. I'm still fairly new to rust and trying to learn. I figure that I learned a lot of Haskell by answering questions, so I should do the same with Rust. Looks like it's working already =) – bheklilr Apr 10 '17 at 19:29
  • I updated that comment with a link to the "why". I started answering Rust questions for the same reason, so I understand where you are coming from! – Shepmaster Apr 10 '17 at 19:31