Rust Book: Chapter 10 Section 2 traits solution with Clone?

Hi folks. I'm trying to implement the alternative solution of using Clone here, but failing: Traits: Defining Shared Behavior - The Rust Programming Language

Might anybody be able to demonstrate a working implementation of the Clone-based solution it refers to, on https://play.rust-lang.org/, please? Was surprised to not be able to locate one with a Google search.

I've successfully implemented the other solutions - but hit some borrow/move errors I couldn't hack my way out of for this one. I'd love to move forward with the book without losing that learning experience! Any help would be very much appreciated, thanks! :slight_smile:

Apparently just asking the question and walking away from the computer momentarily was sufficient for me to devise the solution. I'm now struggling to work out why I even struggled in the first place! :slight_smile:

Here for anybody else in future that is similarly interested: Rust Playground

Thanks to anybody who started looking!

1 Like

The most straightforward changes would be ... pretty much the ones you made, yeah. There is one change I would suggest. Instead of:

        let i = item.clone();
        if i > largest {
            largest = i;
        }

You could do:

        if item > &largest {
            largest = item.clone();
        }

To avoid some clones.

I believe that's what the book was suggesting, and that's fine for practice. However, it's not a great approach in general because we end up potentially cloning all over the place. The second suggestion is a better one, make a largest_ref that returns a &T instead. Then you could have:

fn largest_cloned<T: PartialOrd + Clone>(list: &[T]) -> T {
    largest_ref(list).clone()
}

But more realistically you would just let callers of largest_ref do that if desired (IMO).

Appreciate the elaboration @quinedot. That advanced my understanding of moving. Specifically: reminding me that moving doesn't even happen in an operation such as >, when the underlying value is not being re-assigned to a variable - of course!

It depends on how comfortable you are with references, but I would skip the Clone requirement by just returning a reference to the largest item.

fn largest<T>(items: &[T]) -> &T
where
    T: PartialOrd,
{
    // TODO: Handle empty lists properly
    assert!(!items.is_empty());

    let mut largest = &items[0];

    // Note: Start at 1 because we don't need to compare the 0'th item 
    // with itself
    for item in &items[1..] {  
        if item > largest {
            largest = item;
        }
    }

    largest
}

I'm at the same point in the book and I have a question about his implementation. I wanted to write a method that returned a reference to the element of the list, as you do. My first attempt was similar to yours except I wrote this for loop:

    for &elem in list {
        if elem > largest_elem {
            largest_elem = elem;
        }
    }

This code doesn't compile because elem is of type T and largest_elem is of type &T. I eventually found out that I could solve the problem writing:

    for elem in list {
        if elem > largest_elem {
            largest_elem = elem;
        }
    }

but this doesn't make sense to me, why does calling for &elem in list create an elem of type T while for elem in list results in an elem of type &T?, shouldn't it be the opposite?

&elem is a pattern which matches over any reference &T, copy out its value T and assign it to the new variable named elem.

1 Like

https://h2co3.github.io/pattern/

1 Like