【问题标题】:How do I add a signed integer to an unsigned integer in Rust?如何在 Rust 中将有符号整数添加到无符号整数?
【发布时间】:2019-04-26 11:25:11
【问题描述】:

我是否必须在有符号整数的符号上进行分支,如下例所示? (在实际程序中y被计算为将指向的索引更改为64K数组,并且wraparound是期望的行为)

fn main() {
    let mut x: u16 = 100;
    let y: i8 = -1;
    //x += y;
    if y < 0 {
        x -= i8::abs(y) as u16;
    } else {
        x += i8::abs(y) as u16;
    }
    println!("{}", x);
}

【问题讨论】:

  • @E_net4iskindandwelcoming 链接的问题更多是关于浮点数与整数,而不是混合符号
  • 直觉和行动过程都是一样的。混合符号整数之间的算术运算很棘手,如果编译器只是选择了意外的转换规则集(C 和 C++ 就是这种情况),可能会产生奇怪的结果。如果转换是无损的(例如i16::from(y)),只需使用from 关联函数,否则使用as 运算符。
  • x = x.wrapping_add(y as u16);?
  • 或者更好的是x.wrapping_add(i16::from(y)),以符合cast_lossless Clippy lint。

标签: rust


【解决方案1】:
  • 有符号整数是二进制补码
  • 数字转换符号扩展i8 as u16

这意味着您可以将y as u16 转换为二进制补码值,如果y 为负数,wrapping_add 将正确处理该值。

简而言之:按照@Veedrac 所说的去做。

fn main() {
    let mut x: u16 = 100;
    let y: i8 = -1;
    x = x.wrapping_add(y as u16);
    println!("{}", x);
}

【讨论】:

  • 我不建议这样做,而是使用下一个更高的有符号值(在本例中为 i32)并添加它们。
  • 谢谢,我忘记了 Rust 在无符号溢出时会出现恐慌,而不仅仅是在有符号时。
  • @hellow 需要详细说明吗?首先,这似乎更复杂且容易出错,其次在某些时候 (u128) 你就是不能。
【解决方案2】:

在实际程序中y被计算为将指向的索引更改为64K数组,并且回绕是期望的行为)

对于应该如何做事情没有达成共识,但我的建议是:向用户提供两个功能:

fn add(&mut self, index: u16) -> u16 { // return previous index why not
    // ..
}

fn sub(&mut self, index: u16) -> u16 {
    // ..
}

你也可以添加一个不应该轻易使用的辅助函数:

fn offset(&mut self, offset: i16) -> u16 {
    // ..
}

目的是用户应该知道无论何时使用sub或add,用户应该只管理无符号类型。这个问题是面向意见的,所以如果人们不同意,我可以理解。

完整示例:

use std::mem;

#[derive(Debug, PartialEq, PartialOrd)]
struct MyIndex {
    index: u16,
}

impl MyIndex {
    fn new(index: u16) -> Self {
        Self { index }
    }

    fn add(&mut self, index: u16) -> u16 {
        let index = self.index.wrapping_add(index);
        self.replace(index)
    }

    fn sub(&mut self, index: u16) -> u16 {
        let index = self.index.wrapping_sub(index);
        self.replace(index)
    }

    fn offset(&mut self, offset: i16) -> u16 {
        if offset > 0 {
            self.add(offset as u16)
        } else {
            self.sub(offset as u16)
        }
    }

    fn replace(&mut self, index: u16) -> u16 {
        mem::replace(&mut self.index, index)
    }
}

fn main() {
    let mut index = MyIndex::new(42);

    let mut other_index = MyIndex::new(84);

    let (x, first) = if index > other_index {
        (index.index - other_index.index, true)
    }
    else {
        (other_index.index - index.index, false)
    };

    // ...

    if first {
        index.sub(x);
    }
    else {
        other_index.sub(x);
    }
    println!("{:?} {:?}", index, other_index);

    index.sub(21);
    println!("{:?}", index);

    index.offset(-1);
    println!("{:?}", index);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-24
    • 2013-10-27
    • 2013-08-29
    • 2017-07-21
    • 1970-01-01
    • 1970-01-01
    • 2013-02-04
    相关资源
    最近更新 更多