Как перебирать кортеж объектов признаков или нестандартных типов - PullRequest
2 голосов
/ 10 октября 2019

Этот вопрос был первоначально найден в этом посте в reddit .

Хотя опытный пользователь Rust заметит, что элементы в кортеже не обязательно должны быть одинаковыми (если они, вы должны использовать массив!), и поэтому нет смысла перебирать их, есть некоторые случаи, когда это полезно.

Эти случаи состоят в том, что типы кортежей можно приводить к одному и тому жетип без размера (например, [u8] или dyn Trait).

Демострация:

trait Dummy {}
impl Dummy for () {}
impl Dummy for i32 {}

fn mut_tuple_to_iter(v: &mut ((), i32)) -> impl Iterator<Item = &mut dyn D> {
    //How do I implement this?
}

Я не смог найти красивый способ написать выше. Любая идея?


Чтобы увидеть возможный ответ, который недостаточно красив, вот он:

use core::iter::once;

trait D {}
impl D for () {}
impl D for i32 {}

fn mut_tuple_to_iter(v: &mut ((), i32)) -> impl Iterator<Item = &mut dyn D> {
    once(&mut v.0 as &mut dyn D).chain(once(&mut v.1 as &mut dyn D))
}

Play Ground Link

1 Ответ

1 голос
/ 12 октября 2019

Только что понял, что мне не нужно указывать тип:

fn mut_tuple_to_iter(v:&mut ((), i32)) ->impl Iterator<Item=&mut dyn D> {
    once(&mut v.0 as _).chain(once(&mut v.1 as _))
}

будет работать. Это делает его гораздо менее уродливым!

Конечно, макрос очень поможет:

macro_rules! chained_elements {
    ($exp: expr) => {
        core::iter::once($exp as _)
    };
    ($exp: expr, $($rest:tt)*) => {
        core::iter::once($exp as _)
        .chain(chained_elements!($($rest)*))
    }
}

Теперь вы можете написать

use core::iter::once;

trait D {}
impl D for () {}
impl D for i32 {}

macro_rules! chained_elements {
    ($exp: expr) => {
        core::iter::once($exp as _)
    };
    ($exp: expr, $($rest:tt)*) => {
        core::iter::once($exp as _)
        .chain(chained_elements!($($rest)*))
    }
}

fn mut_tuple_to_iter(v: &mut ((), i32)) -> impl Iterator<Item = &mut dyn D> {
    chained_elements!(&mut v.0, &mut v.1)
}

Детская площадкассылка

Обсуждение

Я давно исследую пространство проектирования в ржавчине, но в некоторых случаях вышеизложенное является единственным решением.

Причинаиз этого следует, что когда вам нужно использовать объекты признаков (например, для уменьшения общего взрыва), так как call-by-value не является опцией (пока), call-by-mutable-reference - лучшая вещь, которую вы можете иметь. В таких случаях картина, подобная приведенной выше, кажется неизбежной.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...