Trait constraint return problem

Hi, guys, I'm learning about trait constraints, but I have a problem. Here's my code:

fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
    let mut largest = list[0];

    for &item in list.iter() {
        if item > largest {
            largest = item;
        }
    }

    largest
}

#[test]
fn test_copy_trait() {
    let numbers = vec![75, 57, 99, 105];

    let result = largest(&numbers);

    println!("{}", result);
}

I understand that trait is a universal parameter. If the data type passed in is a dynamic array, that is, the data allocated on the heap, copy trait cannot be used. If clone is used to replace the copy in the T trait constraint, the performance will be very slow. After checking, I can change the return type to & reference return type. Then I wonder who ownership the return value? at this time?

Sorry, I have a problem here. I don't quite understand

ownership

As you mentioned, a trivial modification to the function uses &T for the return type:

pub fn largest<T: PartialOrd>(list: &[T]) -> &T {
    let mut largest = &list[0];

    for item in list.iter() {
        if item > largest {
            largest = item;
        }
    }

    largest
}

In this case, the owner of the return value is the owner of the list's items; everything is all borrowed. This can be seen by expanding the elided lifetime:

pub fn largest<'a, T: PartialOrd>(list: &'a [T]) -> &'a T { ... }

The list is a slice borrowing any contiguous sequence of T values that live at least as long as 'a, and the signature indicates that the return value lives just as long. We don't necessarily need to know who owns the list or return value, so long as they live long enough for us to borrow them.

If don't care about ownership, use the life cycle to identify the accepted parameters and return parameters of the function. that the life cycle of the caller is less than the life cycle of the function, Is that understandable?

There is only one constraint on the caller's end. The caller can't hold onto the return value longer than its borrow of list, since the return value has the same lifetime as list. (Semantically, the return value is a part of list, so it can only be accessed as long as list can be accessed.) Otherwise, I'm afraid I don't understand what you're asking.

Almost every assertion/assumption you made in the post is incorrect or does not generalize. Let's see one-by-one:

This is not true in itself. The Copy-ability of a value doesn't depend on where it happens to reside in memory. If you put a u32 in a Vec, the u32 elements itself are still trivially copiable.

Do not confuse this with the fact that a Vec itself isn't Copyable; there isn't anything magical or artificial restriction about what is or isn't Copy. It's a purely technical necessity. A vector cannot be Copy because it manages heap memory itself, and it contains a pointer to the buffer it owns. If one were to duplicate it without restriction, then that would copy around the pointer as well, resulting in two Vecs sharing the same buffer pointer. This would lead to a double-free memory corruption error if (or when) both copies were dropped.

However, a Copy type such as u32 doesn't manage any memory. It literally is just the bunch of 32 bits it takes up in memory or in a register or wherever it happens to be. It's trivial to duplicate by just reading the constituent bits and writing the exact same bit pattern elsewhere. There's no double free to worry about. So, wherever a u32 is – on the stack, on the heap, in a register, flying through a wire – it can be copied out of that place and be put wherever else one pleases.

That's also a blanket assertion which is simply false in the case of Copy types (a well-behaved Copy type implements Clone in terms of the bitwise copy as well), and usually falls into the "doesn't matter" category most of the rest of the time. You can clone a couple millions of short Strings around, for example, and most modern computers will do that in the blink of an eye.

Whoever owned it before. Taking references to a value doesn't affect (pretty much by definition) its owner. In your example, numbers owns the vector and the vector owns its elements. So, the returned reference will also point inside the vector, of course.

1 Like

thanks :slight_smile:

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.