如何制作通用的绝对值函数?
How do I make a generic absolute value function?
我正在尝试编写一个通用函数来计算任何有符号整数类型的绝对值。当值是可能的最低负值时,它应该 return 一个错误,例如 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
.
- 我在 "cannot bind by-move into a pattern guard" 的匹配臂上出现负值的通用实现错误(但非通用版本没有。)
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
How do I determine generically the minimum value? Basically the Rust equivalent of the C++ std::numeric_limits<T>::min()
?
您想要 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),
}
}
My generic implementation errors on the match arm for negative values with "cannot bind by-move into a pattern guard" (yet the non-generic version doesn't.)
我添加了一个 Copy
绑定,以避免移动模式守卫中的值的问题。大多数数字类型应该是 Copy
.
也许更好的方法是使用 "checked" 运算符变体,例如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)
}
}
这会将函数的 "meat" 委托给现有代码来完全按照您的要求执行,因此您犯错的空间更小。
我正在尝试编写一个通用函数来计算任何有符号整数类型的绝对值。当值是可能的最低负值时,它应该 return 一个错误,例如 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
. - 我在 "cannot bind by-move into a pattern guard" 的匹配臂上出现负值的通用实现错误(但非通用版本没有。)
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
How do I determine generically the minimum value? Basically the Rust equivalent of the C++
std::numeric_limits<T>::min()
?
您想要 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),
}
}
My generic implementation errors on the match arm for negative values with "cannot bind by-move into a pattern guard" (yet the non-generic version doesn't.)
我添加了一个 Copy
绑定,以避免移动模式守卫中的值的问题。大多数数字类型应该是 Copy
.
也许更好的方法是使用 "checked" 运算符变体,例如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)
}
}
这会将函数的 "meat" 委托给现有代码来完全按照您的要求执行,因此您犯错的空间更小。