Question
In Rust, String::len() returns the number of bytes in the string, not the number of characters. This can be confusing when working with Unicode text.
For example:
let s = String::from("ラウトは難しいです!");
println!("{}", s.len()); // returns 30
The string contains 10 Unicode scalar values, but len() returns 30 because the text is encoded as UTF-8 and each character uses multiple bytes.
I found that this gives the character count I expect:
let count = s.chars().count();
println!("{}", count); // returns 10
Is there any built-in method on String that returns the number of characters directly, other than using s.chars().count()?
Short Answer
By the end of this page, you will understand why Rust strings report their length in bytes, how to count Unicode scalar values with chars().count(), and when that still differs from what users think of as a “character”. You will also learn the practical trade-offs between byte length, char count, and grapheme cluster count.
Concept
Rust String values are stored as UTF-8. UTF-8 is a variable-width encoding, which means:
- Some characters use 1 byte.
- Others use 2, 3, or 4 bytes.
Because of this, Rust's String::len() returns the number of bytes, not the number of human-readable characters.
let s = "hello";
println!("{}", s.len()); // 5 bytes
let s = "ラウト";
println!("{}", s.len()); // more than 3 bytes
In Rust, there are three different ideas that beginners often mix up:
- Bytes: the raw UTF-8 data stored in memory
charvalues: Unicode scalar values- Grapheme clusters: what a user usually sees as one character on screen
For many tasks, s.chars().count() is the correct answer if you want the number of Unicode scalar values. There is no special built-in String method like char_len() that does this directly. The standard Rust approach is:
s.chars().count()
Why Rust does this:
- Byte length is fast to retrieve.
- Random indexing by character is not safe or efficient in UTF-8.
- Rust makes Unicode handling explicit, so you choose the correct unit for your task.
This matters in real programs because text processing can mean very different things depending on the goal:
- Storage size -> use bytes
- Unicode scalar count -> use
chars() - What a user sees as one visible character -> use grapheme clusters from a crate such as
unicode-segmentation
So the short answer is: no, there is no separate built-in String method for character count; s.chars().count() is the normal standard-library solution.
Mental Model
Think of a Rust string like a sentence stored in boxes of varying sizes.
len()asks: how many boxes are being used?chars().count()asks: how many Unicode symbols are stored?- Grapheme counting asks: how many symbols does a person visually see?
These are not always the same.
For example, one visible symbol on screen can be made of:
- one byte
- several bytes
- one
char - multiple
charvalues combined
So when working with strings in Rust, the first question is not “How long is this string?” but rather:
Long in what unit?
Syntax and Examples
The most common string length-related operations in Rust are:
let s = String::from("こんにちは");
println!("bytes: {}", s.len());
println!("chars: {}", s.chars().count());
Example 1: ASCII text
let s = String::from("hello");
println!("bytes: {}", s.len());
println!("chars: {}", s.chars().count());
Output:
bytes: 5
chars: 5
For plain ASCII, bytes and chars are the same.
Example 2: Japanese text
let s = String::from("ラウトは難しいです!");
println!("bytes: {}", s.len());
println!("chars: {}", s.chars().count());
Output:
bytes: 30
chars: 10
Each Japanese character uses multiple bytes in UTF-8, so byte count is larger.
Example 3: Visible characters can still differ
let s = "e\u{301}"; // e + combining accent
println!("bytes: {}", s.len());
println!("chars: {}", s.chars().count());
This may display as a single visible character, but it contains multiple Unicode parts.
If you need user-visible characters
Rust's standard library does not count grapheme clusters directly. For that, developers often use unicode-segmentation:
use unicode_segmentation::UnicodeSegmentation;
let s = "e\u{301}";
println!("graphemes: {}", s.graphemes(true).count());
Use this only when you specifically need what users perceive as characters.
Step by Step Execution
Consider this example:
let s = String::from("aé日");
println!("bytes = {}", s.len());
println!("chars = {}", s.chars().count());
Let's trace it.
Step 1: Create the string
let s = String::from("aé日");
This string contains:
aé日
Step 2: Count bytes with len()
s.len()
In UTF-8:
auses 1 byteéuses 2 bytes日uses 3 bytes
Total:
1 + 2 + 3 = 6 bytes
So:
println!("bytes = {}", s.len()); // 6
Step 3: Count Unicode scalar values with chars().count()
s.chars().count()
chars() iterates over each Unicode scalar value in the string:
aé日
That gives:
3 chars
So:
println!("chars = {}", s.chars().count()); // 3
Important detail
len() is fast because the string already stores its byte length.
chars().count() must walk through the string and decode UTF-8, so it is not a constant-time lookup.
Real World Use Cases
Measuring storage or network size
If you are checking payload size, file size, database limits, or protocol limits, use:
s.len()
This tells you how many bytes the string uses.
Validating a maximum number of Unicode characters
If a rule says “maximum 50 Unicode characters”, use:
s.chars().count()
Example:
if username.chars().count() > 50 {
println!("Username is too long");
}
Limiting what users see on screen
For UI text, emojis, accented characters, and combined symbols, visible length may differ from chars().count(). In that case, grapheme clusters are more appropriate.
Processing multilingual text
When parsing international input, avoid assuming one byte equals one character. Rust's string model helps prevent those mistakes.
Safe iteration over text
Instead of indexing strings directly, Rust developers commonly use:
chars()for Unicode scalar valuesbytes()for raw bytes- grapheme iteration for user-facing text
Real Codebase Usage
In real Rust projects, developers usually choose string length logic based on the requirement rather than looking for one universal "length" method.
Common patterns
Validation
fn is_valid_name(name: &str) -> bool {
let count = name.chars().count();
count >= 2 && count <= 30
}
This is common in forms, APIs, and CLI tools.
Byte-size guards
fn fits_in_header(value: &str) -> bool {
value.len() <= 256
}
Useful when protocols or storage systems define byte limits.
Early returns
fn validate_message(msg: &str) -> Result<(), String> {
if msg.is_empty() {
return Err("message cannot be empty".to_string());
}
if msg.chars().count() > 140 {
return Err("message too long".to_string());
}
Ok(())
}
Explicit Unicode handling
In production code, developers often document what "length" means:
- bytes
- Unicode scalar values
- grapheme clusters
This avoids subtle bugs and confusing validation rules.
Avoiding repeated counts
Because chars().count() walks the string, developers may compute it once and reuse it:
let char_count = s.chars().count();
if char_count > 20 {
println!("too long");
}
Common Mistakes
Mistake 1: Assuming len() means character count
Broken expectation:
let s = "こんにちは";
assert_eq!(s.len(), 5); // wrong
Why it fails:
len()returns bytes, not Unicode scalar values.
Correct approach:
assert_eq!(s.chars().count(), 5);
Mistake 2: Assuming chars().count() is user-visible length
let s = "e\u{301}";
println!("{}", s.chars().count());
This may print 2, even though the user may see one character.
Avoid it by clarifying your requirement:
- Need Unicode scalar values? Use
chars().count() - Need visible characters? Use grapheme clusters
Mistake 3: Trying to index strings by character position
Broken code:
let s = String::from("こんにちは");
let first = s[0];
Rust does not allow this because character boundaries in UTF-8 are not fixed-width.
Use iteration instead:
let first = s.chars().next();
Mistake 4: Recounting repeatedly in a loop
for _ in 0..1000 {
if s.chars().count() > 10 {
println!("long");
}
}
This needlessly recomputes the count many times.
Better:
let count = s.chars().count();
for _ in 0..1000 {
if count > 10 {
println!("long");
}
}
Mistake 5: Using byte slicing carelessly
Broken code:
let s = "ラスト";
let part = &s[0..2];
This can panic if the slice does not align with UTF-8 character boundaries.
Prefer safer approaches such as iterating with chars() when working at character level.
Comparisons
| Task | Recommended Rust approach | What it measures | Notes |
|---|---|---|---|
| Get raw storage length | s.len() | Bytes | Fast and built-in |
| Count Unicode scalar values | s.chars().count() | char values | Standard-library solution |
| Count user-visible characters | s.graphemes(true).count() | Grapheme clusters | Requires unicode-segmentation |
| Iterate over raw encoded data | s.bytes() | Bytes | Useful for low-level work |
| Iterate over Unicode scalar values | s.chars() | char values | Common for text logic |
len() vs chars().count()
| Method | Returns | Constant time? | Built in? |
|---|---|---|---|
len() | Number of bytes | Yes | Yes |
chars().count() | Number of Unicode scalar values | No | Yes |
chars() vs graphemes
| Concept | Example concern | Best choice |
|---|---|---|
| Unicode scalar values | Parsing text logically | chars() |
| What the user sees as one symbol | UI counters, cursor movement | Graphemes |
Cheat Sheet
// Bytes in UTF-8 string
s.len()
// Unicode scalar value count
s.chars().count()
// First Unicode scalar value
s.chars().next()
Rules to remember
String::len()returns bytes, not characters.- Rust strings are UTF-8.
- A
charin Rust is a Unicode scalar value. - One visible character on screen may be made of multiple
charvalues. - There is no built-in
Stringmethod likechar_len(). - The standard way to count scalar values is:
s.chars().count()
Edge cases
- ASCII text: byte count and char count are often the same.
- Non-ASCII text: byte count is often larger.
- Combined Unicode symbols: visible count may differ from
chars().count().
Performance note
len()is cheap.chars().count()scans the string.
If you need visible characters
Use the unicode-segmentation crate for grapheme clusters.
FAQ
Does Rust have a built-in method to count characters in a String?
Not as a dedicated String method. The standard approach is s.chars().count().
Why does String::len() return bytes instead of characters?
Because Rust strings are stored as UTF-8, and byte length is the direct size of the underlying data.
Is chars().count() the same as the number of visible characters?
Not always. It counts Unicode scalar values, which can differ from what users see on screen.
What should I use for user-visible character counts in Rust?
Use grapheme cluster counting, typically with the unicode-segmentation crate.
Is chars().count() slower than len()?
Yes. len() is constant time, while chars().count() must iterate through the string.
Why can't I index a Rust string like s[0]?
Because UTF-8 characters have variable byte lengths, so direct character indexing would be ambiguous and unsafe.
Should I use String or &str for counting characters?
Either works. Methods like len() and chars() are commonly used on &str, and String can be borrowed as &str.
Mini Project
Description
Build a small Rust text analyzer that reports three different kinds of string length: bytes, Unicode scalar values, and whether the string is empty. This project helps reinforce that “string length” depends on what exactly you are measuring.
Goal
Create a program that accepts a few example strings and prints their byte length and character count correctly.
Requirements
- Create a Rust program with at least three example strings, including ASCII and non-ASCII text.
- Print the original string for each example.
- Print the result of both
len()andchars().count(). - Add a simple validation message if the string has more than 10 Unicode scalar values.
Keep learning
Related questions
Absolute Values in Rust: Using the abs() Method
Learn how to calculate absolute values in modern Rust with abs(), handle signed integer overflow, and choose safer alternatives.
Accepting Iterators in Rust Functions with impl Iterator
Learn how to write Rust functions that accept HashMap iterators using generic bounds or impl Iterator, avoiding trait object and lifetime errors.
Access Enum Variant Values in Rust with Pattern Matching
Learn how to extract and print values stored in Rust enum variants using match and if let pattern matching, with practical examples.