如何在Rust中将有符号整数添加到无符号整数?

如何在Rust中将有符号整数添加到无符号整数?,rust,Rust,我是否必须在有符号整数的符号上进行分支,如下面的示例所示?(在实际程序中,y的计算目的是将指向64K数组的索引更改,而wrapparound是所需的行为) fn main(){ 设mut x:u16=100; 设y:i8=-1; //x+=y; 如果y

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

fn main(){
设mut x:u16=100;
设y:i8=-1;
//x+=y;
如果y<0{
x-=i8::abs(y)为u16;
}否则{
x+=i8::abs(y)为u16;
}
println!(“{}”,x);
}
  • 有符号整数是两个补数
  • 数字强制符号将
    i8扩展为u16
这意味着您可以将
y强制转换为u16
,如果
y
为负数,它将变成一个two-s补码值

简言之:照@Veedrac说的做

fn main() {
    let mut x: u16 = 100;
    let y: i8 = -1;
    x = x.wrapping_add(y as u16);
    println!("{}", x);
}
在实际程序中,计算
y
以将指向64K数组的索引更改,而wrapparound是所需的行为)

对于如何操作,目前还没有达成共识,但我的建议是:向用户提供两个功能:

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

@E_Net4;可能与之重复。欢迎链接的问题更多地是关于浮点数与整数,而不是混合符号。直觉以及行动过程都是一样的。混合有符号整数之间的算术很复杂,如果编译器只是选择了一个意外的转换规则集(C和C++就是这种情况),可能会产生奇怪的结果。如果转换是无损的(例如,
i16::from(y)
),则只需使用
from
关联函数,否则使用
as
操作符。
x=x.u添加(y为u16)
?或者更好的是,
x.wrapping\u add(i16::from(y))
,以符合Clippy lint。我不建议这样做,而是使用下一个更高的有符号值(在本例中是
i32
)并添加它们。谢谢,我忘记了,生锈会在无符号溢出时产生恐慌,而不仅仅是在有符号溢出时。@hellow愿意详细说明吗?首先,这看起来更复杂,更容易出错,其次,在某些情况下(
u128
),您就是做不到。
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);
}