Yes, indexing into a string is not available in Rust. The reason for this is that Rust strings are saved in a contiguous UTF-8 encoded buffer internally, so the concept of indexing itself would be ambiguous, and people would misuse it: byte indexing is fast, but almost always incorrect (when your text contains non-ASCII symbols, byte indexing may leave you inside a character / unicode code point, which is really bad if you need text processing), while code point indexing is not free because UTF-8 is a variable-length encoding, so you have to traverse the entire string buffer to find the required code point.

If you are certain that your strings contain ASCII characters only, you can use the as_bytes() method on &str which returns a byte slice, and then index into this slice:

let num_string = num.to_string();

// ...

let b: u8 = num_string.as_bytes()[i];
let c: char = b as char;  // if you need to get the character as a unicode code point

If you do need to index code points, you have to use the chars() iterator:

num_string.chars().nth(i).unwrap()

As I said above, this would require traversing the entire iterator up to the ith code element.

Finally, in many cases of text processing, it is actually necessary to work with grapheme clusters rather than with code points or bytes. For example, many emojis are composed of multiple code points, but are perceived as one "character". With the help of the unicode-segmentation crate, you can index into grapheme clusters as well:

use unicode_segmentation::UnicodeSegmentation

let string: String = ...;
UnicodeSegmentation::graphemes(&string, true).nth(i).unwrap()

Naturally, grapheme cluster indexing into the contiguous UTF-8 buffer has the same requirement of traversing the entire string as indexing into code points.

Answer from Vladimir Matveev on Stack Overflow
Top answer
1 of 10
218

Yes, indexing into a string is not available in Rust. The reason for this is that Rust strings are saved in a contiguous UTF-8 encoded buffer internally, so the concept of indexing itself would be ambiguous, and people would misuse it: byte indexing is fast, but almost always incorrect (when your text contains non-ASCII symbols, byte indexing may leave you inside a character / unicode code point, which is really bad if you need text processing), while code point indexing is not free because UTF-8 is a variable-length encoding, so you have to traverse the entire string buffer to find the required code point.

If you are certain that your strings contain ASCII characters only, you can use the as_bytes() method on &str which returns a byte slice, and then index into this slice:

let num_string = num.to_string();

// ...

let b: u8 = num_string.as_bytes()[i];
let c: char = b as char;  // if you need to get the character as a unicode code point

If you do need to index code points, you have to use the chars() iterator:

num_string.chars().nth(i).unwrap()

As I said above, this would require traversing the entire iterator up to the ith code element.

Finally, in many cases of text processing, it is actually necessary to work with grapheme clusters rather than with code points or bytes. For example, many emojis are composed of multiple code points, but are perceived as one "character". With the help of the unicode-segmentation crate, you can index into grapheme clusters as well:

use unicode_segmentation::UnicodeSegmentation

let string: String = ...;
UnicodeSegmentation::graphemes(&string, true).nth(i).unwrap()

Naturally, grapheme cluster indexing into the contiguous UTF-8 buffer has the same requirement of traversing the entire string as indexing into code points.

2 of 10
54

The correct approach to doing this sort of thing in Rust is not indexing but iteration. The main problem here is that Rust's strings are encoded in UTF-8, a variable-length encoding for Unicode characters. Being variable in length, the memory position of the nth character can't determined without looking at the string. This also means that accessing the nth character has a runtime of O(n)!

In this special case, you can iterate over the bytes, because your string is known to only contain the characters 0–9 (iterating over the characters is the more general solution but is a little less efficient).

Here is some idiomatic code to achieve this (playground):

fn is_palindrome(num: u64) -> bool {
    let num_string = num.to_string();
    let half = num_string.len() / 2;

    num_string.bytes().take(half).eq(num_string.bytes().rev().take(half))
}

We go through the bytes in the string both forwards (num_string.bytes().take(half)) and backwards (num_string.bytes().rev().take(half)) simultaneously; the .take(half) part is there to halve the amount of work done. We then simply compare one iterator to the other one to ensure at each step that the nth and nth last bytes are equivalent; if they are, it returns true; if not, false.

🌐
Reddit
reddit.com › r/rust › what is the best way to index into strings?
r/rust on Reddit: What is the best way to index into Strings?
February 11, 2019 -

I understand there are three things:

  • bytes

  • scalar values

  • graphemes

And due to this, indexing into strings isn't as straightforward as other languages.

I have a large string with only ASCII characters. I do not wish to iterate over it. I just want to index into specific positions of interest. I don't need a range, I just need a single character.

So for example I want to achieve the following. (Python example)

s = "7GATTACA"	#really long string
n = int(s[0])
if n == 7:
	some_complex_operation(s[2],s[7], ..) #passing in more than just these two characters
elif n == 4:
	some_complex_operation(s[2],s[4], ..) #passing in more than just these two characters

I am making this example up, so it's possible there is a workaround, but I'd urge you to play along for the sake of discussion.

I came across a few possibilities:

  • Create a string slice of length 1 for each character? (which can panic, but won't in my case)

  • User char_indices() and use nth()

  • Use chars() and enumerate()

  • Use bytes()

  • Use a crate? Let's say I don't want to use a crate for now (because my use case prevents it).

Correct me if I'm wrong, but in all of these options, I'm either creating extra allocations, or extra iterations over the string/iterator?

What is the best way to address this?

Thank you.

Discussions

Implement Index<usize> for String and &str - libs - Rust Internals
Hello; In a lot of languages, an elegant way exists to get a char from a String. While using Rust no elegant way exists as it is in python or others. There are probably a lot of reasons why this is not in Rust but it is … More on internals.rust-lang.org
🌐 internals.rust-lang.org
1
November 22, 2020
Can slice but can't index an str
Hi, I'm was writing some code in the playground to expericence with strs when I found something strange : str can't be indexed but can be sliced (from a range). Here's an example: let a = "Some cool stuff"; let b = "Another awesome str"; let index: usize = 4; // let a = &a[index]; Error ! let ... More on users.rust-lang.org
🌐 users.rust-lang.org
9
0
April 22, 2021
How to index a string vector
In C, I define char **argv and could use argv[i][j] or *(*(argv+i)+j). But how to do this in Rust? I known that I can use as_bytes() in string, but this works only in 1D array I guess. for example let argv: Vec … More on users.rust-lang.org
🌐 users.rust-lang.org
6
0
September 23, 2019
indexing - How can I find the index of a character in a string in Rust? - Stack Overflow
I have a string with the value "Program", and I want to find the index of character 'g' in that string. More on stackoverflow.com
🌐 stackoverflow.com
🌐
MIT
web.mit.edu › rust-lang_v1.25 › arch › amd64_ubuntu1404 › share › doc › rust › html › book › second-edition › ch08-02-strings.html
Strings - The Rust Programming Language
Rust provides different ways of interpreting the raw string data that computers store so that each program can choose the interpretation it needs, no matter what human language the data is in. A final reason Rust doesn’t allow us to index into a String to get a character is that indexing operations are expected to always take constant time (O(1)).
🌐
Dawchihliou
dawchihliou.github.io › articles › indexing-strings-in-rust-and-typescript
Indexing Strings in Rust and TypeScript: A Case Study of String
December 28, 2021 - So we'll have to iterate through a string slice to access characters by index. Like this: ... The simple task of accessing a character in a string has the time complexity of O(n) instead of O(1). ... We can find the internal representaion of ...
🌐
Rust Internals
internals.rust-lang.org › libs
Implement Index<usize> for String and &str - libs - Rust Internals
November 22, 2020 - Hello; In a lot of languages, an elegant way exists to get a char from a String. While using Rust no elegant way exists as it is in python or others. There are probably a lot of reasons why this is not in Rust but it is very inconvenient to use: string.chars().nth(2) While with Index or a get function: string[2] Or: string.get(2) I think the same methods and implementations as Vec should be in String and &str: get, unsafe get_unchecked, Index If someone can explain to me why it ...
🌐
Rust
doc.rust-lang.org › std › primitive.str.html
str - Rust
Indexes must lie on UTF-8 sequence boundaries. Failing that, the returned string slice may reference invalid memory or violate the invariants communicated by the str type.
🌐
Rust
doc.rust-lang.org › std › string › struct.String.html
String in std::string - Rust
It is more clear, however, how &s[i..j] should work (that is, indexing with a range). It should accept byte indices (to be constant-time) and return a &str which is UTF-8 encoded. This is also called “string slicing”. Note this will panic if the byte indices provided are not character boundaries - see is_char_boundary for more details.
Find elsewhere
🌐
IQCode
iqcode.com › code › rust › how-to-index-a-string-in-rust
how to index a string in rust Code Example
November 12, 2021 - Rust 2022-03-22 13:45:18 rust convert a string (with decimals) to a floating point number. Rust 2022-03-11 20:00:15 creating constants in rust ... Unlock the power of data and AI by diving into Python, ChatGPT, SQL, Power BI, and beyond. Sign up · Develop soft skills on BrainApps Complete the IQ Test ... how ot get a index from string in rust indexing string in rust rust string index char index into a String rust check a current index of a string rust rust char at index in string find index of character rust String index string in place rust index string rust print value of index of string ru
🌐
Better Programming
betterprogramming.pub › indexing-strings-in-rust-and-typescript-a-case-study-of-strings-805b351ca4d6
Indexing Strings in Rust and TypeScript: A Case Study of Strings | by Daw-Chih Liou | Better Programming
December 31, 2021 - Let’s use a classic algorithm is_palindrome to introduce the concept of string indexing. A palindrome, in a very general way of explaining it, is a string that reads the same forward and backward. “Ana” is a palindrome, “A dog!
🌐
Rust
docs.rs › lineindex › latest › lineindex › struct.IndexedString.html
IndexedString in lineindex - Rust
This type holds a reference to an string and an index of both the byte and character ranges for lines within the string. Both of these values are immutable, a change to the original string will require construction of a new indexed string.
🌐
Rust Programming Language
users.rust-lang.org › help
Can slice but can't index an str - help - The Rust Programming Language Forum
April 22, 2021 - Hi, I'm was writing some code in the playground to expericence with strs when I found something strange : str can't be indexed but can be sliced (from a range). Here's an example: let a = "Some cool stuff"; let b = "Another awesome str"; let ...
🌐
Rust Programming Language
users.rust-lang.org › help
How to index a string vector - help - The Rust Programming Language Forum
September 23, 2019 - In C, I define char **argv and could use argv[i][j] or *(*(argv+i)+j). But how to do this in Rust? I known that I can use as_bytes() in string, but this works only in 1D array I guess. for example let argv: Vec …
🌐
Educative
educative.io › answers › what-is-the-stringfind-method-in-rust
What is the string.find() method in Rust?
In Rust, the find() method is used to find the first match of a specified character or another string. It returns the byte index of the first character of the specified character or string in the case of a successful match, and None in case ...
🌐
Rust Programming Language
users.rust-lang.org › help
Why String can be sliced with usize index? - help - The Rust Programming Language Forum
February 6, 2022 - Rust disallows random access to strings, but allows slicing strings using usize ranges, which I think is an inconsistent design. let string = String::from("🌊🌊🌊"); println!("{}", string[1]); // Compile time error: // `String` cannot be indexed by `{integer}` println!("{}", string[1..].chars().next().unwrap()) // Runtime time error: // panicked at 'byte index 1 is not a char boundary; it is inside '🌊' (bytes 0..4) of `🌊🌊🌊`' Rust guarantees that people cannot access strings with usize at the l...
🌐
Medium
medium.com › @jannden › rust-the-most-useful-string-methods-d23c5f1c04c8
Rust: The Most Useful String Methods | Medium
April 1, 2025 - Search a string for a pattern, returning an Option<usize> indicating the start index of the first (.find) or last (.rfind) match.
🌐
Devjunhong
devjunhong.github.io › rust › indexing_string_type
How to get i-th character from String in Rust - Dance with Programming
December 27, 2020 - The debugger tells us about how to store string type data in memory. We need to catch each digit number index (a direct index) represent 1 byte. The “emoji” variable shows how to store the fire emoji.
🌐
crates.io
crates.io › crates › indexed_string
indexed_string - crates.io: Rust Package Registry
March 25, 2022 - A naive implementation for rust's string to support index, works with unicode in O(n) time.
🌐
Reddit
reddit.com › r/rust › learning rust, how do i safely index into strings?
r/rust on Reddit: Learning Rust, how do I safely index into Strings?
March 24, 2026 -

(update at the end)

[Edit: I'm certain I could get away with just using as_bytes, but I'm also taking the opportunity familiarize myself with the Unicode issues, since I've never really worked with that and it seems like Rust supports it well].

I'm a very experienced SW Engineer, but I've never had to work with Unicode stuff. I'm using last year's Advent of Code as an excuse to learn Rust.

I'm using some code from "Rust By Example" to read lines from a file. I'm pretty sure I understand this part; I can print the lines that are read in:

fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>                                                                                                                                                              
where P: AsRef<Path>, {                                                                                                                                                                                                                  
    let file = File::open(filename)?;                                                                                                                                                                                                    
    Ok(io::BufReader::new(file).lines())                                                                                                                                                                                                 
}   

My code is

if let Ok(lines) = read_lines(fname) {
    for line in lines.map_while(Result::ok) {
    // do stuff
    }
}

I'm pretty sure that line is a std::String in my loop; if I'm wrong, please let me know. If a line of input is L34, how can I safely get the L and 34 as separate values? Most of what I see online talk about using chars() and the iterator, but that feels like getting the 34 would be very cumbersome.

Note: I'm avoiding using the word "character" since that seems to be ambiguous (byte vs grapheme).

Updated:

After the helpful responses below, and some looking, I realized that I needed to know string iterators better (I tried to think of them more like C++ iterators). I ended up with this:

if let Ok(lines) = read_lines(fname) {                                                                                                                                                                                                   
    for line in lines.map_while(Result::ok) {                                                                                                                                                                                            
        let mut chars = line.chars();                                                                                                                                                                                                    
        let direction = chars.next().unwrap();                                                                                                                                                                                           
        let num = chars.as_str();                                                                                                                                                                                                        
                                                                                                                                                                                                                                         
        println!("line: {} => {} + {}", line, direction, num);                                                                                                                                                                           
    }                                                                                                                                                                                                                                    
}                                                                                                                                                                                                                                        
Top answer
1 of 12
41
This part of the Rust book might answer some questions you have: https://doc.rust-lang.org/book/ch08-02-strings.html#iterating-over-strings You can also collect an iterator into a Vec, which might provide more of an intuitive interface to the individual characters.
2 of 12
22
line is specifically &str here, which for our purposes is close enough to String. There've been a million words written already about understanding the differences between them, but they're basically identical for the purpose of the string indexing you're asking about. In your shoes, the very specific way I'd solve this problem is strip_prefix, like this: let suffix = line.strip_prefix('L'); suffix is now an Option<&str> that contains either everything after the 'L' or None, if the line didn't start with an L in the first place. More broadly, though, you're talking about parsing, so the answer depends on what specific thing you're trying to parse. Are you trying to unconditionally get the first character? Are you trying to split the string into a numeric half and a non-numeric half? Without knowing the specific thing you're trying to do, I'd spend some time browsing the api surface of the str type, which is filled with all sorts of useful helpers for various string transforms. The most common ones I reach for are strip_prefix, split_at, trim_*, split_once, and find. If I'm taking on a parsing task that's more complex than what can easily be handled by those methods, I'm probably jumping directly into using a dedicated parsing library, probably nom paired with nom-supreme (which I wrote). I've heard that winnow is getting a lot of popularity as something that builds-in a lot of the same parsing ergonomics I developed in nom-supreme.