如何制作通用绝对值函数?

问题描述 投票:1回答:1

我正在尝试编写一个通用函数来计算任何有符号整数类型的绝对值。当该值是可能的最低负值时,它应该返回一个错误,例如,对于8位,abs(-128)不能被表示。

我为i8工作了:

pub fn abs(x: i8) -> Result<i8, String> {
    match x {
        x if x == -128i8 => Err("Overflow".to_string()),
        // I know could just use x.abs() now but this illustrates a problem in the generic version below...
        x if x < 0i8 => Ok(-x),
        _ => Ok(x),
    }
}

fn main() {
    println!("{:?}", abs(-127i8));
    println!("{:?}", abs(-128i8));
}

我无法使用通用版本。具体来说,我有两个问题:

  • 我如何一般确定最小值?什么是C ++ std::numeric_limits<T>::min()的Rust等价物?例如有std::i32::MIN但我不能写std::T::MIN
  • 我在匹配臂上的通用实现错误为负值“无法通过移动到模式保护中绑定”(但非泛型版本没有。)
use num::{traits::Zero, Integer, Signed}; // 0.2.0

pub fn abs<T>(x: T) -> Result<T, String>
where
    T: Signed + Integer + Zero,
{
    match x {
        //x if x == ***rust equivalent of std::numeric_limits<T>::min()** => Err("Overflow".to_string()),
        x if x < T::zero() => Ok(-x),
        _ => Ok(x),
    }
}

fn main() {
    println!("{:?}", abs(-127i8));
    println!("{:?}", abs(-128i8));
}
error[E0008]: cannot bind by-move into a pattern guard
 --> src/main.rs:9:9
  |
9 |         x if x < T::zero() => Ok(-x),
  |         ^ moves value into pattern guard
generics rust traits
1个回答
2
投票

我如何确定最小值?基本上相当于C ++ std::numeric_limits<T>::min()的Rust?

你想要来自Bounded traitnum-traits板条箱的num,它给你一个min_value方法:

pub fn abs<T>(x: T) -> Result<T, String>
where
    T: Signed + Integer + Zero + Neg + Bounded + Copy,
{
    match x {
        x if x == T::min_value() => Err("Overflow".to_string()),
        x if x < T::zero() => Ok(-x),
        _ => Ok(x),
    }
}

我在匹配臂上的通用实现错误为负值“无法通过移动到模式保护中绑定”(但非泛型版本没有。)

我添加了一个Copy绑定,以避免移动模式保护中的值的问题。大多数数字类型应该是Copy

也许更好的是使用“已检查”的运营商变体,例如CheckedSub

pub fn abs<T>(x: T) -> Result<T, String>
where
    T: Signed + Integer + Zero + Neg + CheckedSub,
{
    if x < T::zero() {
        T::zero()
            .checked_sub(&x)
            .ok_or_else(|| String::from("Overflow"))
    } else {
        Ok(x)
    }
}

这会将函数的“肉”委托给现有代码,使其完全符合您的要求,从而减少出错的空间。

© www.soinside.com 2019 - 2024. All rights reserved.