Does this to_owned cost anything and can it be avoided?

Hello,

I encountered what feels like an inconsistency between the implementation of contains() for HashSet and for Vec. It has to do with the fact that HashSet bounds the query argument with T: Borrow<Q> while Vec's contains just takes a &T.

This means that I have to use to_owned() in order to query the Vec using contains().

fn main() {
    
    //HashSets work
    use std::collections::HashSet;
    let mut set : HashSet<Vec<u8>> = HashSet::new();
    set.insert(b"One".to_vec());
    println!("{:?}", set.contains(&b"One"[..]));
    
    //Vecs Don't
    let mut vec : Vec<Vec<u8>> = Vec::new();
    vec.push(b"One".to_vec());
    //println!("{:?}", vec.contains(&b"One"[..]));
    println!("{:?}", vec.contains(&b"One"[..].to_owned()));
}

Does this to_owned() end up making a local copy or is the compiler smart enough to smooth everything out?

Thank you.

Yes, this does involve an allocation and copy for the creation of the temporary vector. To avoid it, you can use an iterator.

fn main() {
    let mut vec : Vec<Vec<u8>> = Vec::new();
    vec.push(b"One".to_vec());
    
    if vec.iter().any(|item| item == b"One") {
        println!("Has One");
    }
    if vec.iter().any(|item| item == b"Two") {
        println!("Has Two");
    }
}
1 Like

Thanks for the reply.

I wonder why Vec's contains() didn't follow the same pattern as HashSet's. This vastly reduces the number of places contains can be used with a Vec. Your implementation is probably very similar what contains() is doing inside anyway, but using a built-in library function feels more elegant, if only it worked as efficiently.

Too bad. Thanks for the reply!

See issue 62367.

3 Likes

Hahahah. It's like reading my internal monologue over the last hour. Good to know I'm not crazy anyway.

Thanks for the link.

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.