如何从一个对象安全的特质对象中移动值?

12

一个Mech搭载了一个驾驶员,这是一个Named实体。在运行时,省略的Mech构造函数会向外部资源查询要使用的具体驾驶员类型。

trait Named {
    fn name(self) -> String;
}

struct Person {
    first_name: String,
    last_name: String
}

impl Named for Person {
    fn name(self) -> String {
        format!("{} {}", self.first_name, self.last_name)
    }
}

pub struct Mech<'a> {
    driver: Box<Named + 'a>,
}

impl<'a> Mech<'a> {
    pub fn driver_name(self) -> String {
        self.driver.name()
    }
}

driver_name方法将所有权返回到String,以便在链接调用中进一步使用(在实际代码中它是一个Command)。如果编译失败,则会出现以下情况:

error[E0161]: cannot move a value of type Named + 'a: the size of Named + 'a cannot be statically determined
  --> src/lib.rs:22:9
   |
22 |         self.driver.name()
   |         ^^^^^^^^^^^

使特征Sized失败的对象安全性:
trait Named: Sized {
    fn name(self) -> String;
}

error[E0038]: the trait `Named` cannot be made into an object
  --> src/lib.rs:17:5
   |
17 |     driver: Box<Named + 'a>,
   |     ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Named` cannot be made into an object
   |
   = note: the trait cannot require that `Self : Sized`

有没有办法实现这个模式?

我是否缺少了什么基本的东西?

如果无法实现,有什么好的解决方法?


8
为什么要使用 self 而不是 &self - Shepmaster
除了采用 take 模式之外,想不到其他的方法:fn take_name(&mut self) -> String是对象安全的,但需要对类型的状态域进行扩展。 - E net4
1个回答

16

正如编译器所提示的那样,由于您正在处理动态分派,因此无法静态确定该特征。 在这种情况下,仍然可以使用self: Box<Self>来实现所有权。

trait Named {
    fn name(self: Box<Self>) -> String;
}

struct Person {
    first_name: String,
    last_name: String,
}

impl Named for Person {
    fn name(self: Box<Self>) -> String {
        format!("{} {}", self.first_name, self.last_name)
    }
}

pub struct Mech<'a> {
    driver: Box<Named + 'a>,
}

impl<'a> Mech<'a> {
    pub fn driver_name(self) -> String {
        self.driver.name()
    }
}

fn main() {}

1
非常感谢,我寻找这样的东西已经很长时间了。我还想问另一件事,如果您可以在这个问题上帮助我:虽然Rust文档通常非常棒,但我大量搜索了它,以寻找像那样的解决方案,并且我确信在Rust by Example、Rust Book或Nomicum中没有类似的东西。而且我对正式参考资料中的大部分内容仍不完全满意,在那里我可能会找到答案。是否有其他来源可以让我看到更多类似的高级模式? - Sam96
1
@Sam96(1)Rust subreddit上有一些关于良好模式和技术内容的博客文章;(2)官方的Zulip和Discord频道是向聪明人提问复杂问题的绝佳场所;(3)就我个人而言,我大部分的Rust知识都是通过破解开源项目获得的。 - Caio
干得好!这里也很有用:https://github.com/fzyzcjy/flutter_rust_bridge/pull/582#discussion_r934064949 - ch271828n

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接