Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't None be cloned for a generic Option<T> when T doesn't implement Clone?

Given a struct with a generic Option<T> where T might not implement Clone why can't None be cloned? Isn't a None of type T the same as any other None? For example:

struct Foo<T> {
    bar: Vec<Option<T>>,
}

impl <T> Foo<T> {
    fn blank(size: usize) -> Foo<T> {
        Foo {
            bar: vec![None; size],
        }
    }
}
like image 224
HiDefender Avatar asked Nov 25 '20 20:11

HiDefender


People also ask

What does derive clone do?

The derive d implementation of Clone calls clone on each field. For a generic struct, #[derive] implements Clone conditionally by adding bound Clone on generic parameters.

What does clone do rust?

Trait std::clone::Clone1.0. A common trait for the ability to explicitly duplicate an object. Differs from Copy in that Copy is implicit and extremely inexpensive, while Clone is always explicit and may or may not be expensive.


2 Answers

As the other answers correctly point ouf, this is due to the way the vec!-macro is implemented. You can manually create a Vec of any Option<T> without requiring T to be Clone:

let bar = std::iter::repeat_with(|| Option::<T>::None).take(size).collect::<Vec<_>>();

This will create size-number of Option::<T>::None and place them in a Vec, which will be pre-allocated to the appropriate size. This works for any T.

like image 149
user2722968 Avatar answered Oct 24 '22 14:10

user2722968


Isn't a None of type T the same as any other None?

Definitely not! Unlike reference-based languages where null is typically implemented as a null-reference, Rust's Option<T> introduces no indirection and stores T inline when the option is Some. Since all enum variants have the same size, the None variant must still occupy at least as much space as T.

Having said that, it is technically true that the None value could be cloned without T being Clone simply because the None variant of the enum doesn't contain the T, it only stores the discriminator and reserves space that could contain T if the variant were to change to Some. But since Rust enum variants are not separate types, a trait bound defined for the enum must cover all variants.

See other answers more detailed explanations and instructions how to create a vector of None values of a non-cloneable Option.

like image 45
user4815162342 Avatar answered Oct 24 '22 15:10

user4815162342