Deriving a trait results in unexpected compiler error, but the manual implementation works

左心房为你撑大大i 提交于 2019-11-26 02:14:53

问题


This code (playground):

#[derive(Clone)]
struct Foo<\'a, T: \'a> {
    t: &\'a T,
}

fn bar<\'a, T>(foo: Foo<\'a, T>) {
    foo.clone();
}

... does not compile:

error: no method named `clone` found for type `Foo<\'a, T>` in the current scope
  --> <anon>:7:9
   |>
16 |>     foo.clone();
   |>         ^^^^^
note: the method `clone` exists but the following trait bounds were not satisfied: `T : std::clone::Clone`
help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `clone`, perhaps you need to implement it:
help: candidate #1: `std::clone::Clone`

Adding use std::clone::Clone; doesn\'t change anything, as it\'s already in the prelude anyway.

When I remove the #[derive(Clone)] and manually implement Clone for Foo, it compiles as expected!

impl<\'a, T> Clone for Foo<\'a, T> {
    fn clone(&self) -> Self {
        Foo {
            t: self.t,
        }
    }
}

What is going on here?

  • Is there a difference between #[derive()]-impls and manual ones?
  • Is this a compiler bug?
  • Something else I didn\'t think of?

回答1:


The answer is buried in the error message:

the method clone exists but the following trait bounds were not satisfied: T : std::clone::Clone

When you derive Clone (and many other automatically-derived types), it adds a Clone bound on all generic types. Using rustc -Z unstable-options --pretty=expanded, we can see what it becomes:

impl <'a, T: ::std::clone::Clone + 'a> ::std::clone::Clone for Foo<'a, T> {
    #[inline]
    fn clone(&self) -> Foo<'a, T> {
        match *self {
            Foo { t: ref __self_0_0 } =>
            Foo{t: ::std::clone::Clone::clone(&(*__self_0_0)),},
        }
    }
}

In this case, the bound is not needed because the generic type is behind a reference.

For now, you will need to implement Clone yourself. There's a Rust issue for this, but it's a comparatively rare case with a workaround.




回答2:


Your example will derive Clone without any problems if you explicitly mark that T should implement Clone, like this:

#[derive(Clone)]
struct Foo<'a, T: 'a> {
    t: &'a T,
}

fn bar<'a, T: Clone>(foo: Foo<'a, T>) {
    foo.clone();
}

(Playground link)

It seems unusual that you can avoid specifying the bound explicitly, but Shepmaster's answer seems to suggest that the compiler inserts it implicitly, so my suggestion is functionally identical.



来源:https://stackoverflow.com/questions/39415052/deriving-a-trait-results-in-unexpected-compiler-error-but-the-manual-implementa

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!