是否有内置函数将数字转换为任何基数中的字符串?

时间:2018-05-10 16:04:33

标签: rust format

我希望替换内部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 :(得分:2)

如果您希望提高性能,可以创建一个结构并为其实现DisplayDebug。这样可以避免分配String。为了最大限度地过度工程,您还可以使用堆栈分配的数组而不是Vec

以下Boiethios' answer应用了这些更改:

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,我没有包含它们。您可以在internal implementation details of the standard library中看到示例代码。

答案 1 :(得分:-1)

这里是一个选项,无需反转(甚至创建)数组。在做 对我来说这似乎效率很低:

use std::char::from_digit;

fn encode(n: u32, r: u32) -> String {
   if n == 0 {
      return String::new()
   }
   let c = from_digit(n % r, r).unwrap_or('!');
   encode(n / r, r) + &String::from(c)
}

fn main() {
   let n = 1577858399;
   let s = encode(n, 36);
   println!("{}", s == "q3ezbz")
}

尽管,如果输入的是数字0,则只会得到一个空的String。 这是解决方法:

fn encode(n: u32, r: u32) -> String {
   let c = from_digit(n % r, r).unwrap_or('!');
   return match n / r {
      0 => String::new(),
      n => encode(n, r)
   } + &String::from(c)
}

https://doc.rust-lang.org/std/char/fn.from_digit.html