如何获得既没有恐慌又不安全的嫌疑人?

时间:2016-10-23 14:02:33

标签: rust

注意:How to get subslices已关闭,但没有约束。

我正在寻找具有此签名的函数的最佳实现:

Nmap done: 1 IP address (1 host up)...

Nmap done: 1 IP address (0 hosts up)... 具有相同的功能,但用>>> X = np.ones((3, 6)) >>> Y = np.ones((6, 3)) * 2 >>> Z1 = np.zeros((6,6)) >>> Z2 = np.zeros((3,3)) >>> >>> np.vstack((Z1, X)) array([[ 0., 0., 0., 0., 0., 0.], [ 0., 0., 0., 0., 0., 0.], [ 0., 0., 0., 0., 0., 0.], [ 0., 0., 0., 0., 0., 0.], [ 0., 0., 0., 0., 0., 0.], [ 0., 0., 0., 0., 0., 0.], [ 1., 1., 1., 1., 1., 1.], [ 1., 1., 1., 1., 1., 1.], [ 1., 1., 1., 1., 1., 1.]]) >>> np.vstack((Y, Z2)) array([[ 2., 2., 2.], [ 2., 2., 2.], [ 2., 2., 2.], [ 2., 2., 2.], [ 2., 2., 2.], [ 2., 2., 2.], [ 0., 0., 0.], [ 0., 0., 0.], [ 0., 0., 0.]]) >>> np.hstack((np.vstack((Z1, X)), np.vstack((Y, Z2)))) array([[ 0., 0., 0., 0., 0., 0., 2., 2., 2.], [ 0., 0., 0., 0., 0., 0., 2., 2., 2.], [ 0., 0., 0., 0., 0., 0., 2., 2., 2.], [ 0., 0., 0., 0., 0., 0., 2., 2., 2.], [ 0., 0., 0., 0., 0., 0., 2., 2., 2.], [ 0., 0., 0., 0., 0., 0., 2., 2., 2.], [ 1., 1., 1., 1., 1., 1., 0., 0., 0.], [ 1., 1., 1., 1., 1., 1., 0., 0., 0.], [ 1., 1., 1., 1., 1., 1., 0., 0., 0.]]) 替换失败案例而不是恐慌。

扭曲是看似不寻常的约束,这个功能不应该:

  • 调用可能fn sub(slice: &[u8], range: Range<usize>) -> Option<&[u8]>;
  • 的函数
  • 使用impl Index<Range<usize>>代码

slice界面的仔细调查引起了我的注意:

但大多数都不合适:

  • panicunsafe可能会恐慌
  • impl Index<Range<usize>>split_at

请允许我将Index<Range<usize>>::index实施为:

from_raw_parts
虽然看起来工作有O(N)的复杂性;相当不满意。

有没有办法做得更好?

2 个答案:

答案 0 :(得分:6)

我将从我喜欢的版本开始。它是get_slice,它使用边界检查切片,您可以查看编译器的优化输出,以验证编译器是否知道它永远不会发生混乱。 ( 1。我同意,“没有恐慌”是一个很好的事情,能够作为一个断言工作; 2 .get_slice将是libstd的一个很好的补充和确实是有计划的。)

/// Return the subslice corresponding to `range`, if it is in bounds
/// and well formed (start <= end).
pub fn get_slice(slice: &[u8], range: Range<usize>) -> Option<&[u8]> {
    if range.start > range.end || range.end > slice.len() {
        None
    } else {
        Some(&slice[range])
    }
}

接下来是一个尝试的解决方案,仍然使用似乎是 O(N)算法编码,但强度降低到 O(1)优化

我们使用切片迭代器以及我们可以将其转换回切片的事实。切片迭代器的.nth()被打开编码以在恒定时间内向前跳转,但遗憾的是反向版本没有。然而,它的循环已经过优化。

pub fn sub(slice: &[u8], range: Range<usize>) -> Option<&[u8]> {
    if range.start > range.end || range.end > slice.len() {
        return None;
    }

    let mut iter = slice.iter();
    let take_front = range.start; 
    let take_back = slice.len() - range.end; 
    if take_front > 0 {
        iter.nth(take_front - 1);
    }
    if take_back > 0 {
        (&mut iter).rev().nth(take_back - 1);
    }
    Some(iter.as_slice())
}

playground link

注意:遗憾的是我认为我们在这里做了一些武断的规则。我们可以在take front操作之后使用.chunks(),它会为您提供直接的 O(1)解决方案。但是,如果要求0大小的块,块可能会出现混乱。这只是在我使用边界检查切片时将它放在同一个括号中(“它可能会引起恐慌”)。

答案 1 :(得分:2)

现在,您只需在切片上使用get方法即可。

我从The document of that method复制了以下代码。

let v = [10, 40, 30];
assert_eq!(Some(&40), v.get(1));
assert_eq!(Some(&[10, 40][..]), v.get(0..2));
assert_eq!(None, v.get(3));
assert_eq!(None, v.get(0..4));