2

这个问题最初是在 reddit 的这篇文章中找到的。

虽然有经验的 Rust 用户会发现元组中的元素不必相同(如果是,则应该使用数组!),因此迭代它们没有意义,但在某些情况下仍然存在这种情况很有用。

这些情况是元组的类型可以转换为相同的未调整大小的类型(例如[u8]or 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))
}

游乐场链接

4

1 回答 1

1

刚刚发现我不必指定类型:

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

游乐场链接

讨论

我一直在 rust 中探索设计空间,但在某些情况下,以上是唯一的解决方案。

其原因是当你必须使用 trait 对象(例如,减少泛型爆炸)时,因为按值调用不是一个选项(还),按可变引用调用是你能做的最好的事情有。在这种情况下,上述模式似乎不可避免。

于 2019-10-11T23:50:44.417 回答