简体   繁体   English

Rust 方法处理数字溢出和有符号/无符号字段 generics

[英]Rust method handling number overflows and signed/unsigned fields with generics

I am currently dealing with a question on Rust, hope this is not a too stupid question.我目前正在处理一个关于 Rust 的问题,希望这不是一个太愚蠢的问题。 The problem I am trying to solve is the following:我要解决的问题如下:

I want to have a struct witch two numeric fields, x and y .我想要一个包含两个数字字段xystruct These numeric fields can be either signed or unsigned.这些数字字段可以是有符号的,也可以是无符号的。 These fields should only be numeric, float or int, but can be signed or unsigned.这些字段只能是数字、浮点数或整数,但可以是有符号或无符号的。

The struct has one method called offset , which allows to increase or decrease the values of the fields.struct有一种称为offset的方法,它允许增加或减少字段的值。 However, the behaviour of the offset method has to change depending on if the fields of the struct are signed or unsigned, because if the fields are unsigned they can never be negative.但是, offset方法的行为必须根据struct的字段是有符号还是无符号而改变,因为如果字段是无符号的,它们永远不会为负。 This problem is illustrated below:这个问题如下图所示:

use std::ops::AddAssign;

#[derive(Debug)]
struct Coords<T: AddAssign> {
    x: T,
    y: T,
}

impl<T: AddAssign> Coords<T> {
    /// Allows to change the values of the fields
    fn offset(&mut self, dx: T, dy: T) {
        self.x += dx;
        self.y += dy;
    }
}

// This works well for signed number. The offset method works for signed integers.
let x: i8 = 0;
let y: i8 = 0;
let mut coords = Coords{ x, y };
coords.offset(-10, -10);
println!("{:?}", coords); // Coords { x: -10, y: -10 }

// However, this does not work if x and y were unsigned
let x: u8 = 0;
let y: u8 = 0;
let mut coords = Coords{ x, y };
// This does not compile.
// Should give the result as Coords { x: 0, y: 0 }
// coords.offset(-10, -10); 

I am trying to write an implementation of the offset method as to handle the scenarios where the fields of Coords can be either float or int, signed or unsigned.我正在尝试编写offset方法的实现来处理Coords的字段可以是 float 或 int、有符号或无符号的场景。 What would be the cleanest and most idiomatic way of solving this?解决这个问题的最干净和最惯用的方法是什么?

I tried playing around with traits from the num crate, but no success so far.我尝试使用num箱子中的特征,但到目前为止没有成功。 I think I could just write two structs, one for unsigned fields and another for signed fields, each of this with a different implementation of the offset method, but I am pretty sure that there is a more idiomatic solution for this in Rust.我想我可以只写两个结构,一个用于无符号字段,另一个用于有符号字段,每个结构都有不同的offset方法实现,但我很确定在 Rust 中有一个更惯用的解决方案。

Thank you:)谢谢:)

You could write a trait to represent your number and the allowed operations on it.您可以编写一个特征来表示您的号码及其允许的操作。 Something like the following:类似于以下内容:

trait CoordType : Copy {
    type Signed;
    fn offset(self, d: Self::Signed) -> Self;
}

You could also add AddAssign and/or SubAssign as requirements for this trait, depending on the intended usage, but they are not needed for this simple example, because the offset() function takes care of everything.您还可以添加AddAssign和/或SubAssign作为此特征的要求,具体取决于预期用途,但对于这个简单的示例不需要它们,因为offset() function 会处理所有事情。

The impls for i8 and u8 would be as follows: i8u8的含义如下:

impl CoordType for i8 {
    type Signed = i8;
    fn offset(self, d: Self::Signed) -> Self {
        self.saturating_add(d)
    }
}

impl CoordType for u8 {
    type Signed = i8;
    fn offset(self, d: Self::Signed) -> Self {
        if d >= 0 {
            self.saturating_add(d as u8)
        } else {
            self.saturating_sub(-d as u8)
        }
    }
}

I'm using saturating_add/sub instead of plain + and - to avoid panics on overflows.我使用saturating_add/sub而不是普通的+-来避免溢出时的恐慌。 If you need that for i16 , u16 , i32 , u32 , etc. then a macro would help a lot.如果您需要i16u16i32u32等,那么宏会有很大帮助。

The implementations for f32 and f64 should be also quite straightforward. f32f64的实现也应该非常简单。

And then your Coords type is trivially implemented as:然后您的Coords类型被简单地实现为:

#[derive(Debug)]
struct Coords<T: CoordType> {
    x: T,
    y: T,
}

impl<T: CoordType> Coords<T> {
    fn offset(&mut self, dx: T::Signed, dy: T::Signed) {
        self.x = self.x.offset(dx);
        self.y = self.y.offset(dy);
    }
}

Here is a link to the playground with that code.这是带有该代码的操场链接

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

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