首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过信道发送Vec<Box<Trait>>

通过信道发送Vec<Box<Trait>>
EN

Stack Overflow用户
提问于 2018-06-12 19:48:46
回答 2查看 824关注 0票数 4

我正试图通过一个频道发送Vec<Box<Trait>>。我想,发送部分起作用了。在对recv()进行Vec之后,我尝试对其进行迭代,并将内部值的引用传递给一个函数,如果出现错误,该函数将失败:

代码语言:javascript
复制
error[E0277]: the trait bound `&std::boxed::Box<AwesomeTrait + std::marker::Send>: AwesomeTrait` is not satisfied
  --> src/main.rs:12:13
   |
12 |             K::abc(&something);
   |             ^^^^^^ the trait `AwesomeTrait` is not implemented for `&std::boxed::Box<AwesomeTrait + std::marker::Send>`
   |
note: required by `K::abc`
  --> src/main.rs:57:5
   |
57 |     pub fn abc<T: AwesomeTrait>(something: &T) {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

有没有办法从Box中获取内在价值?

这是一个最小的复制。

代码语言:javascript
复制
use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel::<Request>();
    let s = Something::new();
    tx.send(Request::Do(s)).unwrap();

    let z = thread::spawn(move || match rx.recv().unwrap() {
        Request::Do(somethings) => for something in somethings.list.iter() {
            K::abc(&something);
        },
    });

    z.join();
}

pub enum Request {
    Do(Something),
}

pub struct Something {
    list: Vec<Box<AwesomeTrait + Send>>,
}

impl Something {
    pub fn new() -> Self {
        Self { list: Vec::new() }
    }

    pub fn from<T: AwesomeTrait + Send + 'static>(something: T) -> Self {
        let mut list = Vec::with_capacity(1);
        list.push(Box::new(something));
        // Self { list }
        Self { list: Vec::new() }
    }

    pub fn push<T: AwesomeTrait + Send + 'static>(&mut self, something: T) {
        self.list.push(Box::new(something));
    }
}

pub trait AwesomeTrait {
    fn func(&self);
}

pub struct X {}

impl AwesomeTrait for X {
    fn func(&self) {}
}

pub struct K {}

impl K {
    pub fn abc<T: AwesomeTrait>(something: &T) {
        &something.func();
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-06-12 21:11:24

请允许我就这一表述的类型发表评论:

代码语言:javascript
复制
for s in somethings.list.iter() {
    K::abc(&s);
}

(为了避免混淆,我重新命名了迭代器变量)。

  • something的类型是:Something
  • something.list的类型是:Vec<Box<AwesomeTrait + Send>>
  • somethings.list.iter()std::slice::Iter<...>类型(不重要)。
  • s&Box<AwesomeTrait + Send>型的。需要注意的是,它是对一个框的引用,因为您使用的是iter()而不是into_iter()

要获得实际的AwesomeTrait,您需要取消引用s以获得Box,然后再取消引用以获得内部对象:**s

但是**sAwesomeTrait类型的,您需要对它进行引用,所以必须使用&**s获取地址,这是&AwesomeTrait类型的地址。

由此产生的代码如下:

代码语言:javascript
复制
for s in somethings.list.iter() {
    K::abc(&**s);
}

或者如果您愿意使用列表:

代码语言:javascript
复制
for s in somethings.list.into_iter() {
    K::abc(&*s);
}

如果您不想考虑使用多少*,可以使用由Box实现的AsRef特性,并信任编译器的自动引用:

代码语言:javascript
复制
for s in somethings.list.iter() {
    K::abc(s.as_ref());
}

注意:.into_iter()也可以滑动。与.iter()一样,如果您迭代对Vec的引用

代码语言:javascript
复制
for s in somethings.list { //consume the list
    K::abc(&*s);
}

或者:

代码语言:javascript
复制
for s in &somethings.list { //do not consume the list
    K::abc(&**s);
}

你以为你已经完成了但还没有..。此代码引发此编译器错误:

代码语言:javascript
复制
error[E0277]: the trait bound `AwesomeTrait + std::marker::Send: std::marker::Sized` is not satisfied
  --> src/main.rs:12:13
   |
12 |             K::abc(&**s);
   |             ^^^^^^ `AwesomeTrait + std::marker::Send` does not have a constant size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `AwesomeTrait + std::marker::Send`
note: required by `K::abc`
  --> src/main.rs:57:5
   |
57 |     pub fn abc<T: AwesomeTrait>(something: &T) {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

为什么会这样呢?好吧,您的K::abc需要对实现AwesomeTrait&AwesomeTrait的类型的引用。但是,一个特征是非大小类型(DST),所有泛型函数类型参数默认都需要Sized类型。

解决方案是将?Sized不需要添加到K::abc中。

代码语言:javascript
复制
impl K {
    pub fn abc<T: AwesomeTrait + ?Sized>(something: &T) {
        something.func();
    }
}

(这个函数中有一个&,它什么也不做,我已经删除了它)。

?Sized的限制是您不能声明T类型的变量或参数,只能声明&T&mut TBox<T>.但是你现在的代码没有什么禁止的,所以没问题。

票数 3
EN

Stack Overflow用户

发布于 2018-06-12 20:54:04

您很可能希望取消引用Box<Trait>,以便返回一个Trait,但这显然是一个不大小的类型,因此您将立即需要引用它,如下所示:

代码语言:javascript
复制
K::abc(&*something)

但是,等等!iter()不使用Vec<Box<Trait>>的所有权,因此每个元素都是&Box<Trait>类型的。要解决这个问题,我们需要调用into_iter()

代码语言:javascript
复制
for something in somethings.list.into_iter() {
    K::abc(&*something);
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50824801

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档