在Rust中对带有Range的HashSet使用.extend()似乎没有任何效果

5t7ly7z5  于 2023-05-29  发布在  其他
关注(0)|答案(1)|浏览(159)

我一直在慢慢地教自己一些Rust,在我最近的奋进中,我正在尝试在Rust中实现一些Maelstrom“工作负载”。
作为Broadcast“工作负载”的一部分,我试图跟踪其他“节点”知道的消息列表,并只返回一组它们不知道的消息,加上一些随机的额外消息(以防某些消息被“丢弃”或其他情况)。)...
但我遇到了一些我无法理解的怪事。下面是我正在尝试做的事情的一个片段(完整源代码在这里):

// start by getting all the values we know the src node doesn't know 
    let src_known = self.neighbors_known_msgs.get(&msg.src).unwrap(); // this ends up being a HashSet<usize> (already checked it exists earlier in method)
    let mut src_unknown: HashSet<_> = self.known_msgs
        .difference(src_known)
        .copied()
        .collect();

    // Now extend that list with an extra set of values
    let list:Vec<_> = self.known_msgs.iter().copied().collect();
    let mut window_size = MIN_WIDOWING_SIZE.max(list.len()/5);
    window_size = window_size.min(list.len());

    // for a first pass, just select the extras randomly, 
    // before trying to implement proper windowing
    let mut rng = rand::thread_rng();
    let extras = (0..=window_size).filter_map(|_| {
        let idx: usize = rng.gen();
        list.get(idx)
    }).cloned();

    // at this point, we have a list of 20% of of the 
    // total messages we know about in the 'extras' range/iterator

    src_unknown.extend(extras);

    // `src_unknown` is unchanged at this point...???
    // and `extras` is not exhausted...???

我设置了一个测试,其中self.known_msgsself.neighbors_known_msgs.get(&msg.src)具有完全相同的100个值的集合,因此.difference(..)导致没有值的集合。
因此,我希望extras有20个值(在debug中显示),在src_unknown.extend(extras);语句执行后,src_unknown中只有这些值……
但实际结果是src_unknown没有变化,extras仍然是Cloned<FilterMap<RangeInclusive<usize>,在调试器中显示iter:{start:0, end:20, exhausted:false}...??
我不明白这里出了什么问题...救命!(提前感谢!))

bejyjqdl

bejyjqdl1#

看看这条线。

let idx: usize = rng.gen();

这将创建一个随机usize。例如,这里有10个随机的usize值。

271997752541285776
12713891318535398239
13268520945444188811
14835789233757821964
16139701502018186282
14874722521942862824
2896522772732415062
12799049362493230697
10493000952461094302
13549460499054734951

一个随机的usize小于100的概率只有0.000000000005%,所以如果你用它来索引一个长度为100的列表,它几乎永远不会在边界内。因此,您创建的是一个筛选器,它可以看到21个None值,然后完成。
要获得想要的行为,可以使用SliceRandom::choose

use rand::seq::SliceRandom;
let extras = (0..=window_size).filter_map(|_| {
    list.choose(&mut rng)
}).cloned();

但是,如果你不想要重复的元素,你可以使用choose_multiple

use rand::seq::SliceRandom;
let extras = list.choose_multiple(&mut rng, window_size).cloned();

相关问题