Отправка Vecпо каналу - PullRequest
       9

Отправка Vecпо каналу

0 голосов
/ 12 июня 2018

Я пытаюсь отправить Vec<Box<Trait>> по каналу.Думаю, отправляющая часть работает.После recv() ing Vec я пытаюсь перебрать его и передать ссылку на внутреннее значение в функцию, которая завершается ошибкой:

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 как-то?

Вот минимальное воспроизведение. :

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();
    }
}

Ответы [ 2 ]

0 голосов
/ 13 июня 2018

Позвольте мне прокомментировать типы этого выражения:

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.

Но **s имеет тип AwesomeTrait, и вам нужна ссылкак этому, поэтому вы должны получить адрес с &**s, который имеет тип &AwesomeTrait.

Полученный код будет:

for s in somethings.list.iter() {
    K::abc(&**s);
}

Или, если вы готовыиспользовать список:

for s in somethings.list.into_iter() {
    K::abc(&*s);
}

Если вы не хотите думать о том, сколько * использовать, вы можете использовать черту AsRef, реализованную Box, и доверять автореференции с помощьюкомпилятор:

for s in somethings.list.iter() {
    K::abc(s.as_ref());
}

Примечание: .into_iter() также можно выделить.Как и .iter(), если вы повторяете ссылку на Vec:

for s in somethings.list { //consume the list
    K::abc(&*s);
}

или:

for s in &somethings.list { //do not consume the list
    K::abc(&**s);
}

Вы думаете, что все готово, но еще не ... этот кодвыдает эту ошибку компилятора:

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:

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

(у вас есть & в этой функции, которая ничего не делает, я ее удалил).

Ограничение ?Sized в том, что вы не можете объявлять переменные или параметрытипа T, только из &T, &mut T, Box<T> ... но ваш текущий код ничего не запрещает, так что нет проблем.

0 голосов
/ 12 июня 2018

Скорее всего, вы захотите разыменовать Box<Trait>, чтобы получить Trait, но это, очевидно, тип без размера, поэтому вам сразу нужно сделать ссылку на него следующим образом:

K::abc(&*something)

Но подождите!iter() не потребляет владения Vec<Box<Trait>>, поэтому каждый элемент имеет тип &Box<Trait>.Чтобы решить эту проблему, нам нужно позвонить into_iter() вместо:

for something in somethings.list.into_iter() {
    K::abc(&*something);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...