gpt4 book ai didi

rust - 将迭代器或集合传递给函数

转载 作者:行者123 更新时间:2023-12-03 11:36:17 24 4
gpt4 key购买 nike

考虑这个伪伪代码。我在下面的keyarg参数上遇到了一些困难,

type MapSet<K,V> = HashMap<K,HashSet<V>>;

fn contract<K,V,V1>(left: &MapSet<K,V>, right: &MapSet<V,V1>,
out: &mut MapSet<K,V1>,
keyarg: Option(__something_iterable__) {

let keys = match keyarg {
Some(keys) => {
keys
},
None => {
left.keys()
},
}

for &k in keys {
// ... do stuff ...
}
}
该功能有时会这样使用,
let x: MapSet<u32,String>;
let y: MapSet<String,u32>;
let out: MapSet<u32,u32>;
let kk: HashSet<u32>;

// ... snip ...

contract(x,y,out,kk);
而且,在其他时候,
let x: MapSet<u32,String>;
let y: MapSet<String,u32>;
let out: MapSet<u32,u32>;
contract(x,y,out,None);
换句话说,有时我会使用 keyarg参数传递一个 Option,并引用一个包含我要迭代的键的 HashSet,有时我想遍历 left参数中包含的所有键,因此 keyarg变得简单 None
但是,到目前为止,我始终遇到了 match的问题,该问题提示None导致 Keys对象,而Some分支到HashSet(类型不匹配错误)。
我的问题是如何定义 keyarg参数,以便 match的分支彼此兼容。也就是说,我想表达一个事实,变量 keys只是可以迭代到编译器的东西。

最佳答案

除非keyarg始终与您的MapSet迭代器匹配,并且在您的伪代码中不匹配,否则您将需要keys作为特征对象。 MapSet<K,V>的迭代器具有特征Iterator<Item = &K>,因此您可以将其匹配为Box,如下所示:

let keys: Box<dyn Iterator<Item = &K>> = match keyarg {
Some(keys) => Box::new(...),
None => Box::new(left.keys()),
}

至于确定 keyarg应该是什么,通用的方法是接受任何匹配的可迭代对象,如下所示:
fn contract<'a, K, V, V1, I: IntoIterator<Item = &'a K>>(
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
left: &'a MapSet<K, V>,
right: &MapSet<V, V1>,
out: &mut MapSet<K, V1>,
keyarg: Option<I>,
) {
let keys: Box<dyn Iterator<Item = &K>> = match keyarg {
Some(keys) => Box::new(keys.into_iter()),
None => Box::new(left.keys()),
};

// ...
}
这对于传递 HashSet非常符合人体工程学,但会导致 None情况出现问题:
// This works
contract(&x, &y, &mut out, Some(&kk));

// This fails with error: "type annotations needed, cannot infer type for type parameter `I`"
contract(&x, &y, &mut out, None);
因此,您必须使用一些不理想的虚拟迭代器类型(例如 NoneBox<...>或其他)来注释 std::iter::Empty
相反,您可以直接使 keyarg成为盒装迭代器:
fn contract_1<'a, K, V, V1>(
left: &'a MapSet<K, V>,
right: &MapSet<V, V1>,
out: &mut MapSet<K, V1>,
keyarg: Option<Box<dyn Iterator<Item = &'a K> + 'a>>,
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
) {
let keys: Box<dyn Iterator<Item = &K>> = match keyarg {
Some(keys) => keys,
None => Box::new(left.keys()),
};

// ...
}
可以这样使用:
contract(&x, &y, &mut out, Some(Box::new(kk.iter())));
contract(&x, &y, &mut out, None);

关于rust - 将迭代器或集合传递给函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65848871/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com