How do I convert from a char array [char; N] to a string slice &str?
Asked Answered
C

3

18

Given a fixed-length char array such as:

let s: [char; 5] = ['h', 'e', 'l', 'l', 'o'];

How do I obtain a &str?

Confirmation answered 13/7, 2016 at 18:28 Comment(4)
Note that : [char; 5] is redundant; the type can be inferred.Modiste
@Shepmaster: I put that there to make the question clearer :)Confirmation
Why would you ever create an array like this? "hello" is 1000% easier and more useful.Nester
@delnan: sometimes I want to create one with characters that are not known at compile time, e.g. [c1, c2, c3].Confirmation
M
23

You can't without some allocation, which means you will end up with a String.

let s2: String = s.iter().collect();

The problem is that strings in Rust are not collections of chars, they are UTF-8, which is an encoding without a fixed size per character.

For example, the array in this case would take 5 x 32-bits for a total of 20 bytes. The data of the string would take 5 bytes total (although there's also 3 pointer-sized values, so the overall String takes more memory in this case).


We start with the array and call []::iter, which yields values of type &char. We then use Iterator::collect to convert the Iterator<Item = &char> into a String. This uses the iterator's size_hint to pre-allocate space in the String, reducing the need for extra allocations.

Modiste answered 13/7, 2016 at 18:31 Comment(6)
Is there an equivalent of the vec! macro for String?Confirmation
@Confirmation I'm not sure I understand. Do you mean String::from("foo") or maybe "foo".to_string()? In some contexts you can also use "foo".into(). You don't really need a macro for anything; those are just function calls. I suppose you could create a method s that calls one of them if they are too long...Modiste
I mean something like str!['h', 'e', 'y'].Confirmation
@Confirmation Why would you want that instead of just "hey"?Modiste
sometimes I want to create one with characters that are not known at compile time, e.g. [c1, c2, c3].Confirmation
@Confirmation perhaps you just want literator.Modiste
M
6

Another quick one-liner I didn't see above:

let whatever_char_array = ['h', 'e', 'l', 'l', 'o'];
let string_from_char_array = String::from_iter(whatever_char_array);

Note: This feature (iterating over an array) was introduced recently. I tried looking for the exact rustc version, but could not...

Molybdenous answered 13/7, 2021 at 21:37 Comment(2)
> This feature (iterating over an array) was introduced recently. I tried looking for the exact rustc version, but could not... std::array::IntoIter was introduced in 1.51 while the impl<T, const N: usize> IntoIterator for [T; N] was introduced in 1.53Pontiff
@Pontiff It was always possible to do it with slices: String::from_iter(&chars). But FromIterator was only introduced to the prelude in 2021.Concentric
T
1

Strings in rust are not stored as a sequence of char values, they are stored as UTF-8.

So to convert an array of "chars" to an &str (string slice) you must copy the data. One option, as mentioned in the other answers, is to use a String, but that implies heap allocation you might want to avoid.

If you want to avoid heap allocation, an alternative approach is to use a fixed-size array as the result buffer. Each char takes up a maximum of 4 bytes in UTF-8, so we can size the array such that it will not overflow with any combination of characters.

let mut buf = [0u8; 20]; 
let mut p = 0;
for c in s {
    p += c.encode_utf8(&mut buf[p..]).len();
}
let result = unsafe { std::str::from_utf8_unchecked(&buf[..p]) };
Torero answered 15/5 at 22:5 Comment(1)
Instead of using unsafe code, prefer to use ArrayString.Concentric

© 2022 - 2024 — McMap. All rights reserved.