After implementing From trait a call to the Into trait fails

I am new to Rust and working through the Rust Exercism track. While working on the Simple Linked List project, I ran into a problem I would like to understand.

All tests for my solution passed, but Clippy warned that I should implement the From trait since it includes Into. A twofer ... I couldn't resist. I implemented From and commented out the existing Into. The compilation failed on the test test_into_vector

The error was:
124 | let s_as_vec: Vec = s.into();
| ^^^^ the trait std::convert::From<simple_linked_list::SimpleLinkedList<{integer}>> is not implemented for std::vec::Vec<i32>

The test code is:

#[test]
#[ignore]
fn test_into_vector() {
    let mut v = Vec::new();
    let mut s = SimpleLinkedList::new();
    for i in 1..4 {
        v.push(i);
        s.push(i);
    }
    let s_as_vec: Vec<i32> = s.into();
    assert_eq!(v, s_as_vec);
}

I tested my From implementation with a new test and the new test is successful. The code for the test is

#[test]
#[ignore]
fn test_from_vector() {
    let mut v :Vec<i32> = Vec::new();
    let mut s: SimpleLinkedList<i32> = SimpleLinkedList::new();
    for i in 1..4 {
        v.push(i);
        s.push(i);
    }
    let s_from_vec = SimpleLinkedList::<i32>::from(v);
    assert_eq!(s, s_from_vec);
}

The code for the From implementation looks like

impl<T: Debug>From<Vec<T>> for SimpleLinkedList<T> {
    fn from(items: Vec<T>) -> Self {
        let mut list: SimpleLinkedList<T> = SimpleLinkedList::new();
        for item in items {
            list.push(item)
        }
        println!("{:?}", list);
        list
    }
}

Why does test_into_vector fail if I only have the From as shown above? Please help me understand what at the moment is misunderstood.

Thanks

Because you've not defined the SimpleLinkedList<T> -> Vec<T> conversion. impl From<Vec<T>> for SimpleLinkedList<T> defines Vec<T> -> SimpleLinkedList<T> conversion.

I don't understand; I am still missing something. Isn't the SimpleLinkedList -> Vec conversion the implementation of Into? If I have implemented From should I need to implement Into? Both Clippy and the documentation appear to indicate that I should not need to implement Into.

When you implemented From<SimpleLinkedList<T>> for Vec<T>, you got implementation for Into<Vec<T>> for SimpleLinkedList<T>, not the other way round. And logically, how could the compiler deduce the way to convert vector into linked list, if you only described the method to do the opposite?

That is exactly what I wanted. I originally implemented Into as follows:

#[allow(clippy::from_over_into)]
impl<T: Debug> Into<Vec<T>> for SimpleLinkedList<T> {
    fn into(self) -> Vec<T> {
        let mut vec_list: Vec<T> = Vec::new();
        for item in self {
            vec_list.push(item)
        }
        //The following line works as well.
        //let vec_list: Vec<_> = self.into_iter().collect();
        vec_list.reverse();
        vec_list
    }
}

Clippy complained, so I implemented From, commented out Into and ended with a compilation error on the test test_into_vector.

Ah, sorry, looks like I myself messed up :slight_smile: You have implemented From<Vec<T>> for SimpleLinkedList<T>, so you get for free Into<SimpleLinkedList<T>> for Vec<T>.

I get the compilation error on the test_into_vector test though. Is it a fault in my implementation of From? Is it a limitation in the generation of the "free" Into? Is it just some silly mistake on my part that escapes me?

Well, if you know how to make list from vector, you also know how to convert vector into list. But you're trying to convert list into vector.

I think you misread what clippy was saying. Clippy has a lint saying that
Into<U> for T should be replaced by
From<T> for U, because implementing From<T> for U automatically provides Into<U> for T.

However, it looks like you have replaced
Into<T> for U with
From<T> for U.

In other words
Into<Vec<T>> for SimpleLinkedList<T> with
From<Vec<T>> for SimpleLinkedList<T>, which provides Into<SimpleLinkedList<T>> for Vec<T>, which is different from what you started out with.

2 Likes

Thank you for explaining my error. I can drop

impl<T: Debug> Into<Vec<T>> for SimpleLinkedList<T> {
    fn into(self) -> Vec<T> {
       ...
    }
}

and all tests pass when when I implement

impl<T: Debug>From<SimpleLinkedList<T>> for Vec<T> {
    fn from(items: SimpleLinkedList<T>) -> Vec<T> {
        let mut vector: Vec<_> = items.into_iter().collect();
        vector.reverse();
        vector
    }
}

Thanks again

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.