This is a very short post to share a Rust gotcha I recently discovered. It can be summed up in this TL;DR</em>, freely adapted from the doc:</p>
For a generic struct, The problematic situation can be seen in the following code:</p>
We would expect In this case, we should rather implement Clone and Copy by hand, and remove the unneeded bounds like so:</p>
#[derive]</code> implements Clone (resp. Copy) conditionally by adding bound Clone (resp. Copy) on generic parameters, which isn't always desired.</p>
</blockquote>
#[derive(</span>Clone</span>,</span> Copy</span>)]</span></span>
struct</span> MyRef</span><'</span>a</span>,</span>T</span>>(</span>&</span>'</span>a T</span>);</span></span>
</span>
fn</span> main</span>() {</span></span>
// v is not Copy, but &v is</span></span>
let</span> v</span> :</span> Vec</span><()></span> =</span> Vec</span>::</span>new</span>();</span></span>
// _r1 = &v; would compile</span></span>
let</span> _r1</span> =</span> MyRef</span>(</span>&</span>v);</span></span>
// _r1 moves into _r2</span></span>
// except if _r1 is copy</span></span>
let</span> _r2</span> =</span> _r1;</span></span>
// Error: use of moved value: _r1</span></span>
_r1;</span></span>
}</span></span></code></pre>
MyRef<'a,T></code> to be Clone and Copy even if T</code> is not Clone or Copy, because it only contains &'a T</code> which is always Copy and Clone. But what the Rust compiler is deriving, is instead:</p>
struct</span> MyRef</span><'</span>a</span>,</span> T</span>>(</span>&</span>'</span>a T</span>);</span></span>
</span>
impl</span><'</span>a</span>,</span> T</span>></span> Clone</span> for</span> MyRef</span><'</span>a</span>,</span> T</span>></span></span>
// Notice this bound</span></span>
where</span></span>
T</span>:</span> Clone</span>,</span></span>
{</span></span>
fn</span> clone</span>(</span>&</span>self)</span> -></span> Self {</span></span>
MyRef</span>((</span>&</span>self</span>.</span>0</span>)</span>.</span>clone</span>())</span></span>
}</span></span>
}</span></span>
</span>
impl</span><'</span>a</span>,</span> T</span>></span> Copy</span> for</span> MyRef</span><'</span>a</span>,</span> T</span>> </span></span>
// Notice this bound</span></span>
where</span> T</span>:</span> Copy</span> {}</span></span></code></pre>
struct</span> MyRef</span><'</span>a</span>,</span> T</span>>(</span>&</span>'</span>a T</span>);</span></span>
</span>
impl</span><'</span>a</span>,</span> T</span>></span> Clone</span> for</span> MyRef</span><'</span>a</span>,</span> T</span>></span></span>
{</span></span>
fn</span> clone</span>(</span>&</span>self)</span> -></span> Self {</span></span>
MyRef</span>((</span>&</span>self</span>.</span>0</span>)</span>.</span>clone</span>())</span></span>
}</span></span>
}</span></span>
</span>
impl</span><'</span>a</span>,</span> T</span>></span> Copy</span> for</span> MyRef</span><'</span>a</span>,</span> T</span>></span></span>
{}</span></span></code></pre>
Arthur::Carcano · Jan 10, 2021
Rust gotcha: deriving Copy and Clone can be too restrictive
0Sign in to vote or save
This site does not allow itself to be embedded. You can still read it on the original site — the toolbar below keeps your place in the directory.
This is a very short post to share a Rust gotcha I recently discovered. It can be summed up in this TL;DR , freely adapted from the doc: For a generic struct, #[derive] implements Clone (resp. Copy) conditionally by adding bound Clone (resp. Copy) on generic parameters, which isn't always desired. The problematic situation can be seen in the following code: #[derive( Clone , Copy )] struct…
Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.