1

I'm having trouble defining a function that returns a vector of Nodefrom the select crate, v0.2.2. I've been adding to this function as I've worked my way through error messages (aided by other questions online), but I can't figure out how to assign the 'a lifetime variable to the return value:

extern crate select;

use select::document::Document;
use select::predicate::*;

fn elems_by_class<'a, Node>(document: &'a Document, class: &str) ->   Vec<Node<>>
    where Vec<Node>: std::iter::FromIterator<select::node::Node<'a>>
{
    document.find(Attr("class", class)).iter().collect::<Vec<Node<>>>()
}

fn main() {}

The error I'm getting is

error: borrowed value does not live long enough
  --> src/main.rs:9:5
   |
9  |     document.find(Attr("class", class)).iter().collect::<Vec<Node<>>>()
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value created here
10 | }
   | - temporary value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the block at 8:0...
  --> src/main.rs:8:1
   |
8  | {
   | ^

How can I assign the 'a lifetime to the function call? I tried (unsuccessfully) using variables, but read that variables created within the function body might cause problems, so abandoned that approach. Have I dug myself too far down the borrow hole, and should this function be defined in a simpler way?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
pithonsmear
  • 115
  • 2
  • 7
  • 1
    Note: you don't *assign* lifetimes, you *document* them. You may think of it as *creating* vs *discovering*, or as the joke goes "But if oxygen was discovered in 1770, how did people breathe before?". The key understanding is that lifetimes exist whether you name them or not; and all you are doing is naming them to better understand their relationships (and have the compiler check them). Maybe I should trademark the *lifetimes are like oxygen* tidbit? Sounds better than burritos too. – Matthieu M. Jan 27 '17 at 13:23

1 Answers1

3

Your core problem is that you've defined a generic type that shadows the real Node:

fn elems_by_class<'a, Node>(document: &'a Document, class: &str)
//                    ^^^^ -- no!

This should have been a duplicate of Expected type parameter, found u8, but the type parameter is u8.

However, the select library (versions 0.2.2 and 0.3.0) appears to have a bug:

impl<'a> Selection<'a> {
    fn iter(&'a self) -> Iter<'a>;
}

This forces the values returned by the iterator to have a lifetime tied to the Selection struct, not the Document.

This appears to have been fixed now:

impl<'a> Selection<'a> {
    pub fn iter<'sel>(&'sel self) -> Iter<'sel, 'a>;
}

But the fix has not been released, so you can't do anything except bug the maintainer to release a new version or you can choose to use the library from the git repository.

Community
  • 1
  • 1
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • That helps, thanks! I removed the "fake" Node, and will try to build from fixed select source. Taking mental notes for presenting questions better, as well! – pithonsmear Jan 26 '17 at 20:29