我正在尝试编写一个通用函数,该函数计算任何有符号整数类型的绝对值。当该值是可能的最低负值时(例如,无法表示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));
}
我无法使用通用版本。具体来说,我有两个问题:
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
答案 0 :(得分:2)
如何一般确定最小值?基本上与C ++
std::numeric_limits<T>::min()
的Rust等效吗?
您希望从num-traits
或num
板条箱中获取Bounded
trait,这为您提供了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)
}
}
这将函数的“作用”委托给了完全符合您想要的功能的现有代码,因此您的错误余地更少了。