简体   繁体   English

如何在 Rust 中将已签名的 integer 添加到未签名的 integer 中?

[英]How do I add a signed integer to an unsigned integer in Rust?

Do I have to branch on the sign of the signed integer, like in the example below?我是否必须在已签名的 integer 的符号上分支,如下例所示? (In the real program y is calculated to change the index pointing into a 64K array, and wraparound is the desired behavior) (在实际程序中,计算y以将指向的索引更改为 64K 数组,并且回绕是所需的行为)

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);
}
  • Signed integers are twos complement 有符号整数是二进制补码
  • numeric cast sign extends an i8 as u16 数字强制转换符号将i8 as u16扩展i8 as u16

That means you can cast y as u16 it will turn into a twos complement value that a wrapping_add will rightfully handle if y was negative. 这意味着您可以将y as u16转换y as u16 ,它将转换为二进制补码值,如果y为负数,则wrapping_add将正确处理。

In short: do as @Veedrac said. 简而言之:按照@Veedrac所说的做。

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

In the real program y is calculated to change the index pointing into a 64K array , and wraparound is the desired behavior) 在实际程序中,计算y来更改指向64K数组的索引,并且回绕是所需的行为)

There is no consensus of how things should be done, but here's my advice: Provide to the user two functions: 对于应该如何做尚无共识,但是我的建议是:向用户提供两个功能:

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

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

You could also add a helper function that should not be used lightly: 您还可以添加一个不应轻易使用的辅助函数:

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

The purpose is that the user should know whenever use sub or add, the user should manage only unsigned type. 目的是使用户在使用sub或add时应该知道,用户应仅管理无符号类型。 That question is opinion oriented so I understand if people don't agree. 这个问题是意见导向的,所以我理解人们是否同意。

Full example: 完整示例:

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);
}

If you're on nightly, we now have the unstable feature mixed_integer_ops .如果您每晚使用,我们现在有不稳定的功能mixed_integer_ops

With this you can do:有了这个,你可以这样做:

#[feature(mixed_integer_ops)]
fn main() {
    let mut x: u16 = 100;
    let y: i8 = -1;
    //x += y;
    x = x.wrapping_add_signed(y); // wraps on overflow
    println!("{}", x);
}

There's wrapping_ , checked_ , saturating_ , and overflowing_ variants, depending on what behavior you want on overflow;wrapping_checked_saturating_overflowing_变体,具体取决于您希望溢出时的行为; and the methods are on both signed and unsigned integers, named _unsigned and _signed respectively (so the above could also be expressed as x = y.wrapping_add_unsigned(x); )并且这些方法都在有符号和无符号整数上,分别命名为_unsigned_signed (所以上面也可以表示为x = y.wrapping_add_unsigned(x);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM