提供将 &self 转换为特征对象的方法
Provided method casting &self to trait object
我有一个特征,我想提供一种方法。该方法将根据一些助手来实现,这些助手在特征内部没有任何业务,并且非常重要,动态多态性比使它们通用更有意义。所以我的代码是
fn use_trait(x: &Trait) {
println!("object says {}", x.needed());
}
trait Trait {
fn needed(&self) -> &str;
fn provided(&self) {
use_trait(self);
}
}
struct Struct();
impl Trait for Struct {
fn needed(&self) -> &str {
"Hello, world!"
}
}
fn main() {
Struct().provided();
}
然而,does not compile,错误:
error[E0277]: the trait bound `Self: std::marker::Sized` is not satisfied
--> <anon>:9:19
|
9 | use_trait(self);
| ^^^^ the trait `std::marker::Sized` is not implemented for `Self`
|
= help: consider adding a `where Self: std::marker::Sized` bound
= note: required for the cast to the object type `Trait`
我理解为什么 - 不能保证有人不会为未确定大小的类型实现特征(从 &T where T: Trait
转换为 &Trait
需要 T: Sized
,但声明不要求)。
但是,建议不会满足我的需要。我可以加
fn needed(&self) -> &str where Self: Sized
但是 needed()
方法 将 无法在 &Trait
上访问(因为 Trait : ?Sized
),这使它变得无用,因为类型(实际有用的类型)总是 处理为 Arc<Trait>
。并添加
trait Trait: Sized
更糟,因为它根本不允许 &Trait
(Trait
作为一个类型没有大小,所以 Trait
类型 not 实现特征 Trait
).
当然我可以简单的
fn use_trait<T: Trait>(x: &T)
但是在实际代码中它背后有很多东西,所以我不希望在那里进行单态化,特别是因为 trait 否则总是作为 trait 对象处理。
有没有什么方法可以告诉 Rust impl Trait
的所有类型都必须调整大小,这里是一个应该适用于所有类型的方法的定义?
您需要在 Trait
及其实现上添加一个 as_trait
函数:
trait Trait {
fn needed(&self) -> &str;
fn provided(&self) {
use_trait(self.as_trait());
}
fn as_trait(&self) -> &Trait;
}
struct Struct();
impl Trait for Struct {
fn needed(&self) -> &str {
"Hello, world!"
}
fn as_trait(&self) -> &Trait {
self as &Trait
}
}
你可以去游乐场试试。 (trait objects)
的加强版:
助手 as_trait
函数可以放在一个辅助特性中,该特性可以为所有试图实现 Trait
的 Sized
类型全面实现。然后 Trait
的实现者不必做任何特殊的事情并且转换工作。
fn use_trait(x: &Trait) {
println!("object says {}", x.needed());
}
trait Trait : AsTrait {
fn needed(&self) -> &str;
fn provided(&self) where Self : AsTrait {
use_trait(self.as_trait());
}
}
trait AsTrait {
fn as_trait(&self) -> &Trait;
}
impl<T : Trait + Sized> AsTrait for T {
fn as_trait(&self) -> &Trait { self }
}
struct Struct();
impl Trait for Struct {
fn needed(&self) -> &str {
"Hello, world!"
}
}
fn main() {
Struct().provided();
}
(在 play 上)。
也可以将 provided
简单地放在辅助特征中,但这样就必须动态分派给 Self
的其他方法,这是不必要的。
更新:实际上,重点是仍然可以覆盖 provided
.
现在可以通过将其通用化来进一步改进上述内容。有 std::makrer::Unsize,在撰写本文时还不稳定。我们做不到
trait Trait : Unsize<Trait>
因为Rust不允许CRTP,幸好在方法上加上约束就够了。所以
fn use_trait(x: &Trait) {
println!("object says {}", x.needed());
}
trait Trait {
fn needed(&self) -> &str;
fn provided(&self) where Self: AsObj<Trait> {
use_trait(self.as_obj());
}
}
trait AsObj<Tr: ?Sized> {
fn as_obj(&self) -> &Trait;
}
// For &'a Type for Sized Type
impl<Type: Trait> AsObj<Trait> for Type {
fn as_obj(&self) -> &Trait { self }
}
// For trait objects
impl AsObj<Trait> for Trait {
fn as_obj(&self) -> &Trait { self }
}
struct Struct();
impl Trait for Struct {
fn needed(&self) -> &str {
"Hello, world!"
}
fn provided(&self) {
println!("Aber dieses Objekt sagt Grüß Gott, Welt!"); // pardon my German, it is rusty.
}
}
fn main() {
let s: &Trait = &Struct();
s.provided();
}
(在 play 上)
这最终使其对其他版本的实现者透明。
我有一个特征,我想提供一种方法。该方法将根据一些助手来实现,这些助手在特征内部没有任何业务,并且非常重要,动态多态性比使它们通用更有意义。所以我的代码是
fn use_trait(x: &Trait) {
println!("object says {}", x.needed());
}
trait Trait {
fn needed(&self) -> &str;
fn provided(&self) {
use_trait(self);
}
}
struct Struct();
impl Trait for Struct {
fn needed(&self) -> &str {
"Hello, world!"
}
}
fn main() {
Struct().provided();
}
然而,does not compile,错误:
error[E0277]: the trait bound `Self: std::marker::Sized` is not satisfied
--> <anon>:9:19
|
9 | use_trait(self);
| ^^^^ the trait `std::marker::Sized` is not implemented for `Self`
|
= help: consider adding a `where Self: std::marker::Sized` bound
= note: required for the cast to the object type `Trait`
我理解为什么 - 不能保证有人不会为未确定大小的类型实现特征(从 &T where T: Trait
转换为 &Trait
需要 T: Sized
,但声明不要求)。
但是,建议不会满足我的需要。我可以加
fn needed(&self) -> &str where Self: Sized
但是 needed()
方法 将 无法在 &Trait
上访问(因为 Trait : ?Sized
),这使它变得无用,因为类型(实际有用的类型)总是 处理为 Arc<Trait>
。并添加
trait Trait: Sized
更糟,因为它根本不允许 &Trait
(Trait
作为一个类型没有大小,所以 Trait
类型 not 实现特征 Trait
).
当然我可以简单的
fn use_trait<T: Trait>(x: &T)
但是在实际代码中它背后有很多东西,所以我不希望在那里进行单态化,特别是因为 trait 否则总是作为 trait 对象处理。
有没有什么方法可以告诉 Rust impl Trait
的所有类型都必须调整大小,这里是一个应该适用于所有类型的方法的定义?
您需要在 Trait
及其实现上添加一个 as_trait
函数:
trait Trait {
fn needed(&self) -> &str;
fn provided(&self) {
use_trait(self.as_trait());
}
fn as_trait(&self) -> &Trait;
}
struct Struct();
impl Trait for Struct {
fn needed(&self) -> &str {
"Hello, world!"
}
fn as_trait(&self) -> &Trait {
self as &Trait
}
}
你可以去游乐场试试。 (trait objects)
助手 as_trait
函数可以放在一个辅助特性中,该特性可以为所有试图实现 Trait
的 Sized
类型全面实现。然后 Trait
的实现者不必做任何特殊的事情并且转换工作。
fn use_trait(x: &Trait) {
println!("object says {}", x.needed());
}
trait Trait : AsTrait {
fn needed(&self) -> &str;
fn provided(&self) where Self : AsTrait {
use_trait(self.as_trait());
}
}
trait AsTrait {
fn as_trait(&self) -> &Trait;
}
impl<T : Trait + Sized> AsTrait for T {
fn as_trait(&self) -> &Trait { self }
}
struct Struct();
impl Trait for Struct {
fn needed(&self) -> &str {
"Hello, world!"
}
}
fn main() {
Struct().provided();
}
(在 play 上)。
也可以将 provided
简单地放在辅助特征中,但这样就必须动态分派给 Self
的其他方法,这是不必要的。
更新:实际上,重点是仍然可以覆盖 provided
.
现在可以通过将其通用化来进一步改进上述内容。有 std::makrer::Unsize,在撰写本文时还不稳定。我们做不到
trait Trait : Unsize<Trait>
因为Rust不允许CRTP,幸好在方法上加上约束就够了。所以
fn use_trait(x: &Trait) {
println!("object says {}", x.needed());
}
trait Trait {
fn needed(&self) -> &str;
fn provided(&self) where Self: AsObj<Trait> {
use_trait(self.as_obj());
}
}
trait AsObj<Tr: ?Sized> {
fn as_obj(&self) -> &Trait;
}
// For &'a Type for Sized Type
impl<Type: Trait> AsObj<Trait> for Type {
fn as_obj(&self) -> &Trait { self }
}
// For trait objects
impl AsObj<Trait> for Trait {
fn as_obj(&self) -> &Trait { self }
}
struct Struct();
impl Trait for Struct {
fn needed(&self) -> &str {
"Hello, world!"
}
fn provided(&self) {
println!("Aber dieses Objekt sagt Grüß Gott, Welt!"); // pardon my German, it is rusty.
}
}
fn main() {
let s: &Trait = &Struct();
s.provided();
}
(在 play 上)
这最终使其对其他版本的实现者透明。