Есть ли встроенная функция, которая преобразует число в строку в любой базе? - PullRequest
0 голосов
/ 10 мая 2018

Я хочу заменить внутренний оператор match и работать со всеми значениями до того момента, когда закончится алфавит. Я знаю, что могу написать сам, но хочу использовать встроенные функции.

fn convert(inp: u32, out: u32, numb: &String) -> Result<String, String> {
    match isize::from_str_radix(numb, inp) {
        Ok(a) => match out {
            2 => Ok(format!("{:b}", a)),
            8 => Ok(format!("{:o}", a)),
            16 => Ok(format!("{:x}", a)),
            10 => Ok(format!("{}", a)),
            0 | 1 => Err(format!("No base lower than 2!")),
            _ => Err(format!("printing in this base is not supported")),
        },
        Err(e) => Err(format!(
            "Could not convert {} to a number in base {}.\n{:?}\n",
            numb, inp, e
        )),
    }
}

Ответы [ 2 ]

0 голосов
/ 11 мая 2018

Если вы хотите повысить производительность, вы можете создать структуру и реализовать для нее Display или Debug. Это позволяет избежать выделения String. Для максимальной чрезмерной инженерии у вас также может быть выделенный в стек массив вместо Vec.

Вот ответ Boiethios с этими изменениями:

struct Radix {
    x: i32,
    radix: u32,
}

impl Radix {
    fn new(x: i32, radix: u32) -> Result<Self, &'static str> {
        if radix < 2 || radix > 36 {
            Err("Unnsupported radix")
        } else {
            Ok(Self { x, radix })
        }
    }
}

use std::fmt;

impl fmt::Display for Radix {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut x = self.x;
        // Good for binary formatting of `u128`s
        let mut result = ['\0'; 128];
        let mut used = 0;
        let negative = x < 0;
        if negative {
            x*=-1;
        }
        let mut x = x as u32;
        loop {
            let m = x % self.radix;
            x /= self.radix;

            result[used] = std::char::from_digit(m, self.radix).unwrap();
            used += 1;

            if x == 0 {
                break;
            }
        }

        if negative {
            write!(f, "-")?;
        }

        for c in result[..used].iter().rev() {
            write!(f, "{}", c)?;
        }

        Ok(())
    }
}

fn main() {
    assert_eq!(Radix::new(1234, 10).to_string(), "1234");
    assert_eq!(Radix::new(1000, 10).to_string(), "1000");
    assert_eq!(Radix::new(0, 10).to_string(), "0");
}

Это все еще можно оптимизировать с помощью:

  • создание массива ASCII вместо char массива
  • инициализация массива без нуля

Поскольку для этих путей требуется unsafe или внешний ящик типа arraybuf , я их не включал. Вы можете увидеть пример кода в внутренних деталях реализации стандартной библиотеки .

0 голосов
/ 10 мая 2018

На данный момент, вы не можете сделать это, используя стандартную библиотеку , но вы можете:

  • использовать мой ящик radix_fmt
  • или сверните свою собственную реализацию:

    fn format_radix(mut x: u32, radix: u32) -> String {
        let mut result = vec![];
    
        loop {
            let m = x % radix;
            x = x / radix;
    
            // will panic if you use a bad radix (< 2 or > 36).
            result.push(std::char::from_digit(m, radix).unwrap());
            if x == 0 {
                break;
            }
        }
        result.into_iter().rev().collect()
    }
    
    fn main() {
        assert_eq!(format_radix(1234, 10), "1234");
        assert_eq!(format_radix(1000, 10), "1000");
        assert_eq!(format_radix(0, 10), "0");
    }
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...