如何将 Rust 中的字符转换为整数,使得 '1' 变成 1?

79

我试图找到给定数字的各位数字之和。例如,134 将会得到 8

我的计划是使用 .to_string() 将数字转换为字符串,然后使用 .chars() 迭代每个数字字符。接下来,我想将迭代中的每个 char 转换为一个整数并将其加到一个变量中。最后,我希望获得这个变量的最终值。

我尝试使用以下代码将 char 转换为整数:


```rust let digit_char = '7'; let digit_int = digit_char.to_digit(10); ```
返回:
```rust let digit_char = '7'; let digit_int = digit_char.to_digit(10); ```
fn main() {
    let x = "123";
    for y in x.chars() {
        let z = y.parse::<i32>().unwrap();
        println!("{}", z + 1);
    }
}

(Playground)

但它导致了这个错误:

error[E0599]: no method named `parse` found for type `char` in the current scope
 --> src/main.rs:4:19
  |
4 |         let z = y.parse::<i32>().unwrap();
  |                   ^^^^^

这段代码完全实现了我想要做的事情,但首先我必须将每个char转换为字符串,然后再转换为整数,以便通过z来增加sum

fn main() {
    let mut sum = 0;
    let x = 123;
    let x = x.to_string();
    for y in x.chars() {
        // converting `y` to string and then to integer
        let z = (y.to_string()).parse::<i32>().unwrap();
        // incrementing `sum` by `z`
        sum += z;
    }
    println!("{}", sum);
}

(游乐场)


当我尝试向其添加内容时,它会给我“二进制操作+不能应用于char类型”的错误提示。 - ritiek
如果您想解析整数,您只需要使用 let v: i32 = x.parse()?;。您能否检查一下这是否与https://dev59.com/-V8d5IYBdhLWcg3wNQNg不重复? - E net4
2
抱歉,可能有些混淆了。它是一个整数值,但它是一个单独的类型,因为你不应该对它进行算术运算。我的问题仍然存在:您期望程序输出什么? - Matthieu M.
@Ritiek:没问题;当我提出一个问题时,由于我已经在这个问题上工作了一段时间,所以上下文对我来说似乎很明显,我也有同样的问题 :) - Matthieu M.
@shepmaster:难道+1不让你感到混乱吗?因为如果它能编译的话,代码会打印出“2,3,4”。 - Christopher Oezbek
@ChristopherOezbek 或许是这样,但这就是“楼主尝试过的”。我猜想他们添加了这个来展示他们想要在结果上使用加法的能力,但这只是我的猜测。 - Shepmaster
4个回答

103

你需要的方法是char::to_digit。它将char转换为给定基数中表示的数字。

你也可以使用Iterator::sum方便地计算序列的总和:

fn main() {
    const RADIX: u32 = 10;
    let x = "134";
    println!("{}", x.chars().map(|c| c.to_digit(RADIX).unwrap()).sum::<u32>());
}

1
如果您不关心转换失败,可以使用flat_map - Shepmaster
@AurevoirXavier 不,我不是那个意思。 - Shepmaster
@Shepmaster的意思是像这样x.chars().flat_map(|x| c.to_digit(RADIX))吗?这是因为展平结果会导致panic或者给出值吗? - aravk33
@aravk33,filter_map 在此处是一个很好的选择,因为它将解开 Option<u32>x.chars().filter_map(|c| c.to_digit(RADIX)). 我会更新答案。 - murla
1
@murlakatamenka 不,我是指 flat_map。请参见 为什么 Option 支持 IntoIterator - Shepmaster
@aravk33 不会引发 panic。请参见 为什么 Option 支持 IntoIterator - Shepmaster

19
my_char as u32 - '0' as u32

现在,有很多关于这个答案需要深入探讨的地方。

它的工作原理是因为ASCII编码(因此UTF-8编码)将阿拉伯数字0-9按升序排列。您可以获取标量值并进行减法运算。

但是,对于超出此范围的值应该怎么处理呢?如果提供'p'会发生什么?它会返回64。那么'.'呢?这将导致出现问题。而'♥'将返回9781。

字符串不仅仅是字节序列。它们是UTF-8编码的,您不能忽略这个事实。每个char可以容纳任何Unicode标量值。

这就是为什么使用字符串来解决问题是错误的抽象。

从效率的角度来看,分配字符串似乎是低效的。 Rosetta Code有一个使用迭代器的示例,它只执行数值操作:

struct DigitIter(usize, usize);

impl Iterator for DigitIter {
    type Item = usize;
    fn next(&mut self) -> Option<Self::Item> {
        if self.0 == 0 {
            None
        } else {
            let ret = self.0 % self.1;
            self.0 /= self.1;
            Some(ret)
        }
    }
}

fn main() {
    println!("{}", DigitIter(1234, 10).sum::<usize>());
}

5

如果c是你的字符,你可以直接写:

c as i32 - 0x30;

使用以下进行测试:

let c:char = '2';
let n:i32 = c as i32 - 0x30;
println!("{}", n);

输出:

2

NB: 0x30 在 ASCII 表中代表字符 '0',这个很容易记住!


2
为什么不使用'0'作为i32? - prehistoricpenguin
1
我曾经黑客攻击ROM,所以我养成了将十六进制转换为相应值的习惯。我认为0x30-0x39对应0-9,在任何操作系统上都适用,并且易于记忆。 - Antonin GAVREL

4

另一种方法是迭代字符串中的字符,使用fold进行转换并添加。

fn sum_of_string(s: &str) -> u32 {
  s.chars().fold(0, |acc, c| c.to_digit(10).unwrap_or(0) + acc)
}

fn main() {
    let x = "123";
    println!("{}", sum_of_string(x));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接