Having trouble with iterators (and elements with &&)


#1

Hey everyone, I’m just starting to learn Rust and have been working on the Exercism exercises for it. I’ve been fumbling my way through this one exercise for a while and I feel like I’m starting to get a handle on things, but I’ve hit this strange error that I just cannot seem to fix. I’ve included the source code and error message below and if anyone has any advice or insight it would be greatly appreciated.

pub fn anagrams_for<'a>(source: &str, inputs: &[&'a str]) -> Vec<&'a str> {
    // Break the source string into a Vector of chars and sort them for comparison
    let sourceVec: Vec<char> = source.chars().collect::<Vec<char>>();
    sourceVec.sort();
    // Iterate through the inputs array and filter only the elements that satisfy anagram_for
    let res = inputs.iter().filter(|&x| anagram_for(sourceVec, *x)).collect();
    // return the Vec of anagrams (or an empty vec)
    res
}

fn anagram_for(sortedSource: Vec<char>, input: &str) -> bool {
    // If an element is a different length than source word, it can't be an anagram
    if sortedSource.len() != input.len() {
        return false
    } else {
        // create an element-by-element tuple of the two words and then compare them
        let zipped = sortedSource.iter().zip(input.chars());
        if zipped.filter(|&x| *x.0 != x.1).count() > 0 {
            return false;
        }
        return true;
    }
}

fn main() {
    let inputs = ["tan", "stand", "at"];
    anagrams_for("ant", &inputs);
}

This throws the error:

src/lib.rs:6:69: 6:78 error: the trait `core::iter::FromIterator<&&str>` is not implemented for the type `collections::vec::Vec<&str>` [E0277]
src/lib.rs:6     let res = inputs.iter().filter(|&x| anagram_for(sourceVec, *x)).collect();
                                                                                 ^~~~~~~~~
src/lib.rs:6:69: 6:78 help: run `rustc --explain E0277` to see a detailed explanation
src/lib.rs:6:69: 6:78 note: a collection of type `collections::vec::Vec<&str>` cannot be built from an iterator over elements of type `&&str`
error: aborting due to previous error

I’ve tried adding more type annotations (on the collect, for instance) to try and make sure everything is explicit, and I’ve also tried dereferencing different pieces of the filter, but so far nothing has worked. :frowning:


#2

.collect() uses the FromIterator<T> trait to construct the resulting collection, and you are trying to make a vector of string slices (&str) from an iterator of references to string slices (&&str). The reason why you ended up in that situation is that .iter() creates an iterator over references to the the elements of input, and not the elements themselves.

You can’t fix this by changing the filter, since it’s only inspecting the elements, and not affecting them in any way. That’s why the input to the filter is of the type &&&str. What you can do is add a simple .map(...) call to the chain, that dereferences the elements. This works because the elements, themselves, are actually also references and their lifetimes are larger than the function call.

let res = inputs.iter().filter(|&x| anagram_for(sourceVec, *x)).map(|&x| x).collect();

#3

There are a few issues with your code, such as not using snake cases and crazy use of references, but mainly what you should be using is the cloned() method. Then you don’t have to worry about trying to dereference anything.

let res = inputs.iter().filter(|x| anagram_for(source_vec, x)).cloned().collect();