将无符号整数类型和有符号整数类型相加的概括。

6
我希望有一个Rust函数,允许将(,)类型加到(,)类型上,并检查溢出。
我的实现方式:
/// Add u32 to i32. In case of an overflow, return None.
fn checked_add_i32_u32(a: i32, b: u32) -> Option<i32> {
    let b_half = (b / 2) as i32;
    let b_rem = (b % 2) as i32;

    Some(a.checked_add(b_half)?.checked_add(b_half)?
        .checked_add(b_rem)?)
}

/// Add u64 to i64. In case of an overflow, return None.
fn checked_add_i64_u64(a: i64, b: u64) -> Option<i64> {
    let b_half = (b / 2) as i64;
    let b_rem = (b % 2) as i64;

    Some(a.checked_add(b_half)?.checked_add(b_half)?
        .checked_add(b_rem)?)
}

我有另一个类似的函数可以对和执行相同的操作。感觉在重复自己。这些函数的测试看起来也非常相似。
是否有一种方式可以重构我的代码,只使用一个函数?我不确定如何泛化和之间的关系(或者和,和)。

简化代码,去除最后一个 ?a.checked_add(b_half)?.checked_add(b_half)?.checked_add(b_rem) - Shepmaster
@Shepmaster:好的,谢谢! - real
1个回答

7

您可以使用宏:

trait CustomAdd: Copy {
    type Unsigned;

    fn my_checked_add(self, b: Self::Unsigned) -> Option<Self>;
}

macro_rules! impl_custom_add {
    ( $i:ty, $u:ty ) => {
        impl CustomAdd for $i {
            type Unsigned = $u;

            fn my_checked_add(self, b: $u) -> Option<$i> {
                let b_half = (b / 2) as $i;
                let b_rem = (b % 2) as $i;

                Some(self.checked_add(b_half)?.checked_add(b_half)?
                    .checked_add(b_rem)?)
            }
        }
    }
}

impl_custom_add!(i32, u32);
impl_custom_add!(i64, u64);
// etc.

#[test]
fn tests() {
    assert_eq!(123.my_checked_add(10_u32), Some(133));
}

1
提供信息,我在我的箱子中使用这种策略(https://gitlab.com/Boiethios/radix_fmt_rs/blob/master/src/lib.rs#L66),它运行良好。 - Boiethios

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接