此问题最初在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))
}
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)
}
讨论我已经在锈蚀领域探索了很长时间,但是在某些情况下,上述是唯一的解决方案。
其原因是,当必须使用特征对象(例如,以减少通用爆炸)时,由于按值调用不是一种选择(到目前为止),按可变引用调用是最好的选择你可以有。在这种情况下,像上面这样的模式似乎是不可避免的。