【问题标题】:Downcasting array length & indices向下转换数组长度和索引
【发布时间】:2017-06-15 07:16:28
【问题描述】:

我正在实现二进制搜索。该函数在数组中找到目标值时返回其索引,否则返回-1

我更喜欢处理 i32 而不是 usize 的索引,因为我需要在未找到目标时允许返回 -1 的负数。我明确地在函数的边缘投射,我认为这不是很好。有什么比这更生锈的方法?

fn binary_search(nums: &[i32], target: i32) -> i32 {
    let num_size: i32 = nums.len() as i32;            // This seems bad
    bsearch(nums, target, 0, num_size as usize)
}

fn bsearch(nums: &[i32], target: i32, lo: usize, hi: usize) -> i32 {
    if hi < lo {
        return -1;
    }

    let mid_idx = lo + ((hi - lo) / 2);
    let guess = nums[mid_idx];

    if guess > target {
        bsearch(nums, target, lo, mid_idx - 1)
    } else if guess < target {
        bsearch(nums, target, mid_idx + 1, hi)
    } else {
        mid_idx as i32                      // This seems bad
    }
}

【问题讨论】:

标签: arrays types casting rust


【解决方案1】:

您不必要地与语言抗争。 i32 不是数组索引的合适类型。相反,你应该使用Option:

fn binary_search(nums: &[i32], target: i32) -> Option<usize> {
    let num_size = nums.len();
    bsearch(nums, target, 0, num_size)
}

fn bsearch(nums: &[i32], target: i32, lo: usize, hi: usize) -> Option<usize> {
    if hi < lo {
        return None;
    }

    let mid_idx = lo + ((hi - lo) / 2);
    let guess = nums[mid_idx];

    if guess > target {
        bsearch(nums, target, lo, mid_idx - 1)
    } else if guess < target {
        bsearch(nums, target, mid_idx + 1, hi)
    } else {
        Some(mid_idx)
    }
}

鉴于处理数组的函数已经使用usize 作为索引,强制它使用i32 没有任何好处。如果你想i32是因为你想“找不到”是-1,你可以在函数完成后进行转换。


注意:另外,请记住,在使用i32 时,您确实应该进行边界检查。在 64 位系统上,数组长度可以大大超过 i32 可以表示的长度,即使在 32 位机器上,您也面临着数组索引为负数的风险。

【讨论】:

  • 我同意Option 比哨兵值更干净,但是我认为关于大小的评论最好作为脚注。 “尤其是在 64 位系统上,其中数组长度可以大大超过 i32 可以表示的长度”是理论上的,但在实践中您处理超过 20 亿个元素的数组的频率如何?除了零大小类型,20 亿个元素对于最小可能的元素大小(u8)来说至少是 2GB,并且大小从那里向上。大多数软件程序只是不必处理任何大小的集合,因此强调它可能会削弱答案。
  • @MatthieuM。我稍微改写了一下,但我不知道还有多少脚注——因为它已经是最后一段了。
  • 我拍了一张,如果你不喜欢,请随时回复。
猜你喜欢
  • 1970-01-01
  • 2017-10-13
  • 2018-02-22
  • 2016-08-31
  • 2021-08-10
  • 2014-03-22
  • 1970-01-01
  • 2016-06-25
  • 1970-01-01
相关资源
最近更新 更多