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)
有两种方法:
isize选择铁锈)stdusize并处理标志(显然是我的首选)。但实施取决于你;例如,您可以使用 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)
这一点也不难看;你只需要使用一些特征来隐藏逻辑,然后你只需要使用它。
从 Rust 1.66 开始,标准库现在有checked_add_signed、overflowing_add_signed、saturating_add_signed和wrapping_add_signed。
最简单的方法是创建自己的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函数。