Как мне сделать универсальную функцию абсолютного значения? - PullRequest
0 голосов
/ 14 февраля 2019

Я пытаюсь написать универсальную функцию, которая вычисляет абсолютное значение любого целочисленного типа со знаком.Он должен возвращать ошибку, когда значение является наименьшим возможным отрицательным значением, например, для 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));
}

Я не могу заставить работать универсальную версию.В частности, у меня есть две проблемы:

  • Как определить общее минимальное значение?Что такое Rust-эквивалент C ++ std::numeric_limits<T>::min()?Например, есть 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

1 Ответ

0 голосов
/ 14 февраля 2019

Как определить общее минимальное значение?В основном эквивалент Rust C ++ std::numeric_limits<T>::min()?

Вы хотите Bounded черта из ящиков num-traits или num, что дает вам min_value method:

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)
    }
}

Это делегирует «мясо»функция существующего кода, которая делает именно то, что вы хотите, чтобы у вас было меньше места для ошибок.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...