Bernard
Bernard

Reputation: 5686

Why does std::vec::Vec implement two kinds of the Extend trait?

The struct std::vec::Vec implements two kinds of Extend, as specified hereimpl<'a, T> Extend<&'a T> for Vec<T> and impl<T> Extend<T> for Vec<T>. The documentation states that the first kind is an "Extend implementation that copies elements out of references before pushing them onto the Vec". I'm rather new to Rust, and I'm not sure if I'm understanding it correctly.

I would guess that the first kind is used with the equivalent of C++ normal iterators, and the second kind is used with the equivalent of C++ move iterators.

I'm trying to write a function that accepts any data structure that will allow inserting i32s to the back, so I take a parameter that implements both kinds of Extend, but I can't figure out how to specify the generic parameters to get it to work:

fn main() {
    let mut vec = std::vec::Vec::<i32>::new();
    add_stuff(&mut vec);
}

fn add_stuff<'a, Rec: std::iter::Extend<i32> + std::iter::Extend<&'a i32>>(receiver: &mut Rec) {
    let x = 1 + 4;
    receiver.extend(&[x]);
}

The compiler complains that &[x] "creates a temporary which is freed while still in use" which makes sense because 'a comes from outside the function add_stuff. But of course what I want is for receiver.extend(&[x]) to copy the element out of the temporary array slice and add it to the end of the container, so the temporary array will no longer be used after receiver.extend returns. What is the proper way to express what I want?

Upvotes: 1

Views: 664

Answers (1)

phimuemue
phimuemue

Reputation: 36071

From the outside of add_stuff, Rect must be able to be extended with a reference whose lifetime is given in the inside of add_stuff. Thus, you could require that Rec must be able to be extended with references of any lifetime using higher-ranked trait bounds:

fn main() {
    let mut vec = std::vec::Vec::<i32>::new();
    add_stuff(&mut vec);
}

fn add_stuff<Rec>(receiver: &mut Rec)
    where
        for<'a> Rec: std::iter::Extend<&'a i32>
{
    let x = 1 + 4;
    receiver.extend(&[x]);
}

Moreover, as you see, the trait bounds were overly tight. One of them should be enough if you use receiver consistently within add_stuff.

That said, I would simply require Extend<i32> and make sure that add_stuff does the right thing internally (if possible):

fn add_stuff<Rec>(receiver: &mut Rec)
    where
        Rec: std::iter::Extend<i32>
{
    let x = 1 + 4;
    receiver.extend(std::iter::once(x));
}

Upvotes: 2

Related Questions