【问题标题】:How to iterate over tuple of trait objects or unsized types如何迭代 trait 对象或无大小类型的元组
【发布时间】:2019-10-10 11:20:48
【问题描述】:

这个问题最初是在this post in 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

【问题讨论】:

  • 唯一的困难来自您希望 mutable 引用元组项的要求,我相信这只有在不安全的代码中才有可能。对于共享引用,这很容易实现。
  • 不,那不是真的。我会更新帖子,你会看到的。
  • 好吧,你证明我错了。在这种特殊情况下,您确实可以在函数本身中创建所有必要的可变引用,因此编译器可以验证每个元组元素仅被可变引用一次。可变长度的集合通常需要可变迭代器的不安全代码,因为编译器无法证明每个引用只返回一次。
  • 老实说,我会为这种特定情况使用宏。
  • 它丑的原因是因为你不应该这样做。

标签: rust iterator trait-objects mutable-reference


【解决方案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)
}

Playground link

讨论

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

原因是当你必须使用 trait 对象时(例如,减少泛型爆炸),因为 call-by-value 不是一个选项(目前),call-by-mutable-reference 是最好的你可以拥有的东西。在这种情况下,上述模式似乎是不可避免的。

【讨论】:

    猜你喜欢
    • 2016-05-07
    • 2013-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-28
    • 2012-07-09
    相关资源
    最近更新 更多