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

snu*_*182 2 oop casting traits rust

试图重写一个特点偏色问题,描述在这里.坚持实现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);
}
Run Code Online (Sandbox Code Playgroud)

但由于某些原因,这部分的编译因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);
}
Run Code Online (Sandbox Code Playgroud)

并导致:

<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`
Run Code Online (Sandbox Code Playgroud)

这可以解决吗?

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

ken*_*ytm 5

首先,selfin 的类型fn who_am_i_inner已经是一个参考,所以你不需要&.

fn who_am_i_inner(&self) -> Side {
    Side::Good(self)
}
Run Code Online (Sandbox Code Playgroud)

然后,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`
Run Code Online (Sandbox Code Playgroud)

不可否认,错误信息非常不清楚,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`
Run Code Online (Sandbox Code Playgroud)

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

fn who_am_i_inner(&self) -> Side where Self: Sized {
    Side::Good(self)
}
Run Code Online (Sandbox Code Playgroud)

现在它的工作原理.

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


where Self: Sized是除锈的方法,以表明该方法不能从特质对象使用.我们说如果你喜欢C++,那么方法会从"o​​bject-safety"中忽略,或者"不能是虚拟的".

结果是,如果你所有的都是luke: &GoodDude,那么你就不能打电话,luke.who_am_i_inner()因为它*luke有一个未知的大小.

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

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

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