首页 文章

Rust trait对象的&self不能用于特征默认函数

提问于
浏览
1

试图覆盖特征演员问题,描述here . 坚持实现trait函数,该函数返回带有自己实现的枚举实例:

//the "trait matcher" enum
enum Side<'a> {
    Good(&'a GoodDude),
    Bad(&'a BadDude),
}

//very general trait
trait Dude {
    fn who_am_i(&self) -> Side;
    fn do_useful_stuff(&self);
}

//specific trait #1
trait GoodDude: Dude {
    fn who_am_i_inner(&self) -> Side {
        Side::Good(&self)
    }

    fn save_the_world(&self);
}

//specific trait #2
trait BadDude: Dude {
    fn who_am_i_inner(&self) -> Side {
        Side::Bad(&self)
    }

    fn do_evil(&self);
}

但由于某种原因,这部分的编译失败了E0277

trait GoodDude: Dude {        
    fn who_am_i_inner(&self) -> Side {
        Side::Good(&self) //&self should be &GoodDude, but compiler says it is not...
    }

    fn save_the_world(&self);
}

并导致:

<anon>:16:20: 16:25 error: the trait `GoodDude` is not implemented for the type `&Self` [E0277]
<anon>:16         Side::Good(&self)
                             ^~~~~
<anon>:16:20: 16:25 help: see the detailed explanation for E0277
<anon>:16:20: 16:25 note: required for the cast to the object type `GoodDude`

这可以解决吗?

完整样本:https://play.rust-lang.org/?gist=8ae2384e401da76c16214c4a642ce8b4&version=stable&backtrace=0

1 回答

  • 5

    首先, fn who_am_i_innerself 的类型已经是引用,因此您不需要 & .

    fn who_am_i_inner(&self) -> Side {
        Side::Good(self)
    }
    

    然后,rustc抱怨......

    <anon>:13:20: 13:24 error: the trait `core::marker::Sized` is not implemented for the type `Self` [E0277]
    <anon>:13         Side::Good(self)
                                 ^~~~
    <anon>:13:20: 13:24 help: see the detailed explanation for E0277
    <anon>:13:20: 13:24 note: `Self` does not have a constant size known at compile-time
    <anon>:13:20: 13:24 note: required for the cast to the object type `GoodDude`
    

    不可否认,错误信息非常不清楚,E0277是完全不同的 . 让我们尝试使用nightly编译器,它会提供更好的错误消息:

    error: the trait bound `Self: std::marker::Sized` is not satisfied [--explain E0277]
      --> <anon>:13:20
    13 |>         Side::Good(self)
       |>                    ^^^^
    help: consider adding a `where Self: std::marker::Sized` bound
    note: required for the cast to the object type `GoodDude`
    

    好的,让我们尝试添加 where Self: Sized

    fn who_am_i_inner(&self) -> Side where Self: Sized {
        Side::Good(self)
    }
    

    现在它的工作原理 .

    世界得救了 . 按任意键继续5月4日和你一起Pew Pew Pew Luke我是你的父亲


    where Self: Sized 是Rust表示the method cannot be used from trait objects的方式 . 我们说如果您喜欢C,则忽略"object-safety"或"cannot be virtual"的方法 .

    结果是,如果你所有的都是 luke: &GoodDude ,那么你就不能调用 luke.who_am_i_inner() ,因为 *luke 的大小未知 .

    我们需要使该方法不是对象安全的原因是由于演员 &Self → &GoodDude . 在Rust中,像 &GoodDude 这样的特征对象引用是一个胖指针,在内部它表示为一个2元组 (pointer, method_table) . 但是,在特征中, self 是一个瘦指针 .

    我们无法将精简指针转换为胖指针,因为缺少信息method_table . 如果我们知道具体类型,就可以填写 . 这就是我们添加 where Self: Sized 的原因 .

    如果要使 who_am_i_inner 对象安全,则无法提供默认实现 .

相关问题