Search code examples
stringreferencerust

Converting a char to &str


I have a match statement which returns a &str:

match k {
    SP_KEY_1 => "KEY_1",
    SP_KEY_2 => "KEY_2",
    SP_KEY_3 => "KEY_3",
    SP_KEY_4 => "KEY_4",
    SP_KEY_5 => "KEY_5",
    SP_KEY_6 => "KEY_6",
    _ => (k as char), // I want to convert this to &str
}.as_bytes()

I have tried to convert a char to a string first, and then taking a slice of that:

&(k as char).to_string()[..]

But that gave me the lifetime error:

error[E0597]: borrowed value does not live long enough

Stating that (k as char).to_string() is a temporary value, which makes sense as from what I can tell to_string() returns a clone.

I can add .to_string() to every &str literal above to make the return value String, but that seems both ugly (a lot of repeated code), and probably inefficient, as to_string() clones the original string slice.

The specific question is how would I make a char into a &str, but the broader question is that is there a better solution, what is commonly done this situation.


Solution

  • So long as you don't need to return the &str from the function, you can completely avoid heap allocation using char::encode_utf8:

    const SP_KEY_1: u8 = 0;
    const SP_KEY_2: u8 = 1;
    const SP_KEY_3: u8 = 2;
    const SP_KEY_4: u8 = 3;
    const SP_KEY_5: u8 = 4;
    const SP_KEY_6: u8 = 5;
    
    fn main() {
        let k = 42u8;
    
        let mut tmp = [0; 4];
    
        let s = match k {
            SP_KEY_1 => "KEY_1",
            SP_KEY_2 => "KEY_2",
            SP_KEY_3 => "KEY_3",
            SP_KEY_4 => "KEY_4",
            SP_KEY_5 => "KEY_5",
            SP_KEY_6 => "KEY_6",
            _ => (k as char).encode_utf8(&mut tmp),
        };
    
        println!("{}", s);
    }
    

    This could be paired with a closure if you needed more control:

    fn adapt<F, B>(k: u8, f: F) -> B
    where
        for<'a> F: FnOnce(&'a str) -> B,
    {
        let mut tmp = [0; 4];
    
        let s = match k {
            SP_KEY_1 => "KEY_1",
            SP_KEY_2 => "KEY_2",
            SP_KEY_3 => "KEY_3",
            SP_KEY_4 => "KEY_4",
            SP_KEY_5 => "KEY_5",
            SP_KEY_6 => "KEY_6",
            _ => (k as char).encode_utf8(&mut tmp),
        };
    
        f(s)
    }
    
    fn main() {
        adapt(0, |s| println!("{}", s));
        let owned = adapt(0, |s| s.to_owned());
    }
    

    Or stored in a struct to provide a little bit of abstraction:

    #[derive(Debug, Default)]
    struct Foo {
        tmp: [u8; 4],
    }
    
    impl Foo {
        fn adapt(&mut self, k: u8) -> &str {
            match k {
                SP_KEY_1 => "KEY_1",
                SP_KEY_2 => "KEY_2",
                SP_KEY_3 => "KEY_3",
                SP_KEY_4 => "KEY_4",
                SP_KEY_5 => "KEY_5",
                SP_KEY_6 => "KEY_6",
                _ => (k as char).encode_utf8(&mut self.tmp),
            }
        }
    }
    
    fn main() {
        let mut foo = Foo::default();
        {
            let s = foo.adapt(0);
        }
        {
            let s = foo.adapt(42);
        }
    }