Strings Best Practices
How to Use This List
- Review APIs taking
Stringeverywhere. - Audit UTF-8 assumptions before Windows/path work.
A - API Types
- Accept
&str(orimpl AsRef<str>) for read-only inputs. Caller flexibility. - Return
Stringwhen caller owns result. Borrow only when tied to input lifetime. - Use
Cow<str>when mutation is rare. Avoid forced allocation. - Use
Path/PathBuffor filesystem paths. NotStringpaths. - Use
OsStringwhen preserving non-UTF-8 OS bytes. Windows env vars.
B - UTF-8 Correctness
- Never index
strby byte withoutis_char_boundary. Prevent panics. - Use
chars()for Unicode scalars; graphemes for UI.unicode-segmentation. - Validate external bytes with
from_utf8. Do notunwrapin production. - Do not assume
len()is character count. Document byte length. - Normalize when comparing user text (NFC).
unicode-normalizationif needed.
C - Performance
- Preallocate with
with_capacitywhen size known. Join/build loops. - Prefer
push_strover+in loops.+moves left operand. - Reuse
Stringbuffers withclear. Hot formatting paths. - Compile regex once (
LazyLock). Not per line. - Avoid
to_string/clonein tight loops. Profile with dhat.
D - FFI and Security
- CString rejects interior NUL. Validate before FFI.
- Document lifetime of pointers passed to C. Who frees?
- Redact secrets in Display/Debug logs. Custom impls.
- Validate parse input; no
unwrapon user data. ReturnResult. - Sanitize before shell invocation. Not regex alone.
FAQs
String vs &str param?
&str default; String when taking ownership.Arc?
Shared immutable text.bytes API?
Protocol binary not str.serde skip empty?
skip_serializing_if str is_empty.clippy to_string?
unnecessary_to_owned.inline strings?
smallstr for cache keys.fmt compile time?
format_args! sometimes.i18n?
Gettext external - std no locales.sqlx strings?
bind str refs.next?
Modules and crates organization.Related
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.