【问题标题】:how to add a negative i32 number to an usize variable?如何将负 i32 数添加到 usize 变量?
【发布时间】:2019-01-04 08:56:29
【问题描述】:

如:

let mut a : usize = 0xFF;
a += -1;  // -1 may be from other variable, so there can't be a -= 1;
println!("{}", a);

输出是:

error[E0277]: the trait bound `usize: std::ops::Neg` is not satisfied

不管怎样?

【问题讨论】:

  • 很遗憾,错误信息对您没有多大帮助。
  • 您是坚持使用usize,还是可以改用isize?或者更好的是,像i64这样的已知位宽类型?
  • @MatthieuM。实际上是数组的索引,只能是$usize$

标签: rust integer integer-overflow unsigned-integer


【解决方案1】:

您的尝试不起作用,因为在 Rust 中,您只能在严格相似的类型之间进行操作。 Rust 不执行任何隐式数字转换,因为它会像你在下面看到的那样是脚下的射击:你有一个特殊情况和几种溢出的方法。

一种方法是将i32 的绝对值转换为usize,并根据它是负数还是正数来添加或删除它。但是,您必须处理取其绝对值时溢出的最小值的特殊情况:

fn add(u: usize, i: i32) -> usize {
    if i.is_negative() {
        u - i.wrapping_abs() as u32 as usize
    } else {
        u + i as usize
    }
}

fn main() {
    let u = 7;
    let i1 = -1;
    let i2 = 1;
    let min = -2_147_483_648;

    assert_eq!(add(u, i1), 6);
    assert_eq!(add(u, i2), 8);
    assert_eq!(add(3_000_000_000, min), 852_516_352);
}

您还可以验证溢出:

fn add(u: usize, i: i32) -> Option<usize> {
    if i.is_negative() {
        u.checked_sub(i.wrapping_abs() as u32 as usize)
    } else {
        u.checked_add(i as usize)
    }
}

fn main() {
    let u = 7;
    let i1 = -1;
    let i2 = 1;

    assert_eq!(add(u, i1), Some(6));
    assert_eq!(add(u, i2), Some(8));
    assert_eq!(add(0, -1), None);
}

【讨论】:

  • 似乎条件跳转的成本大于隐式转换。在numeric cast之后添加只需要忽略OF位即可。
  • @ExcosyS.P.检查的操作有(非常小的)成本。但是,据我所知,显式转换并不比隐式转换慢。在这两种情况下都有相同的演员表。
  • 也许我没听懂你的问题:你的号码总是负数吗?
  • 非常感谢。此外,我想知道为什么不支持 rust 中的隐式数字转换。
  • @ExcosyS.P.隐式数字转换是危险的,因为您可能会得到意想不到的结果:如果编译器默默地将负 i32 转换为带有two's complement 的使用大小怎么办?结果更可能出乎意料。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-22
  • 2019-09-13
  • 1970-01-01
相关资源
最近更新 更多