如何从usize中减去isize?

Rip*_*ead 7 primitive types type-conversion rust

我有一个usize确实达到了非常大的值。我还对它应用了一个增量,我以isize. 在不损失任何精度的情况下应用增量的最佳方法是什么?

fn main() {
    let mut big_indexer: usize = 4295032832; // 2^32 + 2^16
    let delta: isize = -65792; // 2^16 + 2^8

    let big_indexer = (big_indexer as isize) + delta // Can't do this b/c overflow
    let big_indexer = big_indexer + (delta as usize) // Can't do this b/c lose negative number

    // This is ugly
    if delta < 0 {
        let big_indexer -= delta.abs() as usize;
    } else {
        let big_indexer += delta.abs() as usize;
    }
}
Run Code Online (Sandbox Code Playgroud)

Sta*_*eur 5

有两种方法:

  • 要么将所有价值保持在以下范围内(例如isize选择铁锈)std
  • 或者您只与自己合作usize并处理标志(显然是我的首选)。

但实施取决于你;例如,您可以使用 abool来告诉您偏移量是差异还是相加,或者使用枚举:

fn foo(n: usize, offset: usize, sub: bool) -> Option<usize> {
    (if sub {
        usize::checked_sub
    } else {
        usize::checked_add
    })(n, offset)
}

enum OffSet {
    Neg(usize),
    Pos(usize),
}

fn bar(n: usize, offset: OffSet) -> Option<usize> {
    match offset {
        OffSet::Pos(offset) => n.checked_add(offset),
        OffSet::Neg(offset) => n.checked_sub(offset),
    }
}

fn main() {
    let n = 4295032832; // 2^32 + 2^16
    let offset = 65792; // 2^16 + 2^8
    let sub = true;
    assert_eq!(Some(n - offset), foo(n, offset, sub));
    assert_eq!(Some(n - offset), bar(n, OffSet::Neg(offset)));
}
Run Code Online (Sandbox Code Playgroud)

这一点也不难看;你只需要使用一些特征来隐藏逻辑,然后你只需要使用它。


Loc*_*cke 5

Rust 1.66(2022 年 12 月 15 日稳定发布)

从 Rust 1.66 开始,标准库现在有checked_add_signedoverflowing_add_signedsaturating_add_signedwrapping_add_signed

Rust 1.13(2020 年 9 月 10 日)*

最简单的方法是创建自己的add_signed函数或特征。该函数如下所示。此实现应在发布模式下提供最佳性能,同时正确处理溢出检查(如果启用)。当 rustc 在发布模式下编译时(禁用溢出检查),此函数生成与a.wrapping_add(b as usize).

#[track_caller]
#[inline(always)]
pub const fn add_signed(a: usize, b: isize) -> usize {
    match b {
        x if x < 0 => a - x.wrapping_abs() as usize,
        x => a + x as usize
    }
}
Run Code Online (Sandbox Code Playgroud)

* 要与 Rust 1.13 完全兼容,您必须将其删除#[track_caller]并将其转换为非const函数。