Converting 0, 1, 2, .., 9 to '0', '1', .., '9'

let x: i32, be a value >=0 and <= 9

I want to convert ‘x’ to a char ‘c’

If this was plain C, we could abuse all types of things and do:

char c = (char) ('0' + x)

With this being rust, what is the best way to do this conversion?

Basically I need the inverse of

EDIT: @mbrubeck’s solution is better, you should rather use that one.

let c: char = match x {
    | 0 ..= 9 => ('0' as u8 + x as u8).into(),
    | _ => unimplemented!("Handle other case"),
1 Like

See also std::char::from_digit.


Sorry for derailing the conversation abit here, but I’m just curious as to why I’ve seen this syntax many times and have never read about it:

match foo() {
    | 0..128 => println!("7 bit number!"),
//  ^ This 
    | 128..256 => println!("8 bit number!")
//  ^ And this

I’m just curious as to how it’s meant to be interpreted, or if it’s just a visual guide.


I think it’s the same sort of thing as allowing trailing commas when passing arguments to a function or in a struct definition. When you’ve got several branches with different patterns allowing that leading | probably leads to “nicer” looking code and less noisy diffs, while still being unambiguous to rustc's parser.

1 Like

Yep, that’s it, @Michael-F-Bryan guessed correctly.

The first reason is that I was used to leading pipes in enum arms to begin with (OCaml style).

The reason to replicate the style in Rust (after discovering that it was valid Rust :)), is that I like to keep the coding style consistent no matter how big the code block is, and I have found that for huge enum matches, having the initial pipe makes the match more readable / easier to spot within the code, imho (patterns being between a pipe | and the arrow =>):

use ::core::mem::drop as do_stuff_with;

enum Kind { A, B, C }

struct BigStruct {
    kind: Kind,
    foo: i32,
    bar: Inner,

enum Inner {

fn example (x: &'_ BigStruct)
    match *x {
        | BigStruct {
            kind: Kind::A,
            bar: Inner::Named(ref name),
        | BigStruct {
            kind: Kind::B,
            bar: Inner::Named(ref name),
        => {
            let new_name: String =
                    .map(|c| match c {
                        | '-' => '_',
                        |  _  => c,

        | _ => {
            unimplemented!("This is just an example");

Your example just made me realize that this

match name {
    | "Jan" | "Piet" | "Koos" => do_something(),
    | _ => unimplemented!("No match!"),

is like switch fallthrough in C/C++.

switch name {
    case "Jan":
    case "Piet":
    case "Koos": {
        std::cout << "No match!";

The difference being, in C/C++ you have to remember to opt out (more error-prone), while in Rust you have to opt in (less error-prone). Yay for more safety! :wink: