我想将isize
添加到usize
,并包括边界检查,这样结果就不会溢出usize
的边界。如何做到这一点?
您可以使用isize::is_negative()
、isize::wrapping_abs()
、usize::checked_add()
和usize::checked_sub()
的组合。
const fn add(lhs: usize, rhs: isize) -> Option<usize> {
if rhs.is_negative() {
lhs.checked_sub(rhs.wrapping_abs() as usize)
} else {
lhs.checked_add(rhs as usize)
}
}
为什么isize::is_negative()
与rhs < 0
?在这种情况下,它不会改变任何内容,因为对文字的逻辑运算算作常量表达式。
然而,虽然它对文字是允许的,但通常是不允许的,因为traits方法不能是const
。因此,如果你有一个包装类型,例如Foo(isize)
,那么在const上下文中就不允许说foo < Foo(0)
。然而,可以说foo.is_negative()
作为Foo
仍然可以实现const fn is_negative()
。
是的,你仍然可以说foo.0 < 0
,但这不是我想要表达的观点
实现这一点的一种方法是使用如下函数:
fn signed_unsigned_add(x: usize, y: isize) -> usize {
let (n, overflow) = x.overflowing_add(y as usize);
if (y >= 0) ^ overflow {
n
} else {
panic!(
"signed + unsigned addition overflow: {} + {}",
x,
y,
)
}
}
这利用了这样一个事实,即当从无符号数的角度来看时,这样的加法应该仅为"0";溢出";当无符号数为负数时(即表现出二补码行为(,如果当数字为负数时没有这样做,则表示下溢。