Rust 特征对象的 &self 不能在特征默认函数中使用
Rust trait object's &self cannot be used in a trait default function
试图覆盖 here 描述的特征投射问题。坚持实现特征函数,其中 returns 枚举实例内部有自己的实现:
//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
首先,fn who_am_i_inner
中self
的类型已经是一个引用,所以你不需要&
。
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 是完全不同的东西。让我们尝试使用夜间编译器,它会提供更好的错误消息:
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)
}
现在可以使用了。
World saved. Press any key to continue
May the 4th be with you
Pew Pew Pew
Luke I am yr father
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
这样的特征对象引用是一个 胖指针 ,在内部它表示为一个二元组 (pointer, method_table)
。然而,在一个特征中 self
是一个瘦指针。
我们无法将瘦指针转换为胖指针,因为缺少信息 method_table。如果我们知道具体类型,就可以填写。这就是我们添加 where Self: Sized
.
的原因
如果你想让 who_am_i_inner
对象安全,那么你不能提供默认实现。
试图覆盖 here 描述的特征投射问题。坚持实现特征函数,其中 returns 枚举实例内部有自己的实现:
//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
首先,fn who_am_i_inner
中self
的类型已经是一个引用,所以你不需要&
。
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 是完全不同的东西。让我们尝试使用夜间编译器,它会提供更好的错误消息:
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)
}
现在可以使用了。
World saved. Press any key to continue
May the 4th be with you
Pew Pew Pew
Luke I am yr father
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
这样的特征对象引用是一个 胖指针 ,在内部它表示为一个二元组 (pointer, method_table)
。然而,在一个特征中 self
是一个瘦指针。
我们无法将瘦指针转换为胖指针,因为缺少信息 method_table。如果我们知道具体类型,就可以填写。这就是我们添加 where Self: Sized
.
如果你想让 who_am_i_inner
对象安全,那么你不能提供默认实现。