Things on this page are fragmentary and immature notes/thoughts of the author. Please read with your own judgement!
:timing
:sccache 1Tips and Traps¶
Rust has 2 popular string types
Stringandstr(there are more string types in Rust but won’t be covered here).Stringcan be MUTABLE (different from Java and Python) and is heap-allocated whilestris an immutable sequence of UTF-8 bytes somewhere in memory (static storage, heap or stack).Stringowns the memory for it whilestrdoes NOT. Since the size ofstris unknown, one can only handle it behind a pointer. This means thatstrmost commonly appears as&str: a reference to some UTF-8 data, normally called a string slice or just a slice .&strvsStringis similar toslicevsarrayorVec.&Stringis a reference to aStringtype and is also called a borrowed type. It is nothing more than a pointer which you can pass around without giving up ownership.&Stringcan be coerced to a&strimplicitly.If you want a rea-only view of a string,
&stris preferred. If you want to own and mutate a string,Stringshould be used. For example,Stringshould be used for returning strings created within a function or (usually) when storing sstrings in a struct or enum.Indexing into a string is not available in Rust. The reason for this is that Rust strings are encoded in UTF-8 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, which is really bad if you need text processing) while char indexing is not free because UTF-8 is a variable-length encoding, so you have to traverse the entire string to find the required code point.
There are 2 ways to get chars out of a string. First, you can call the
charsmethod which returns an iterator. This ways is not efficient of course if you want random access. Second, you can get the underlying bytes representation of a string by calling theas_bytesmethod (which returns a byte slice&[u8]. You can then index the byte slice and convert au8variable tocharusing theaskeyword.let my_str = "Hello World";defines a&str(notString).If you have a
&strand want a newString, you can clone it either byto_owned()orto_string()(they are effectively the same). Both of those 2 methods will copy the memory and make a new String.
Convert &str to String¶
There are many ways to covnert a &str to a String.
&str.to_string&str.to_ownedString::from&str.into(Intois the reciprocal ofFrom)String.push_str
The first 4 ways are equivalent. For more detailed discussions, please refer to How do I convert a &str to a String in Rust? .
Convert String to &str¶
Assume s is a value of String,
there are (at least) 3 way to convert it to &str.
&s[..]&*ss.as_str()s.as_ref()
I personally perfer as.as_str() or s.as_ref().
let s = "how are you".to_string();
s"how are you"s.as_str()"how are you"{
let s2: &str = s.as_ref();
s2
}"how are you"&str vs String vs AsRef<str> for Function Parameters¶
&stris preferred overStringas function paraemters unless you really need to own a string value in the function (in which case you needString).If you need even a more generic string parameter or if you need a generic item type for a collection, you have to use
AsRef<str>. For more discussions, please refer to AsRef .
&str¶
Primitive, immutable, fixed length.
let mut s: &str = "how are you";
s"how are you"let s2 = String::from("abc");
s2[0]s2[0]
^^^^^ `String` cannot be indexed by `{integer}`
the type `String` cannot be indexed by `{integer}`
help: the trait `Index<{integer}>` is not implemented for `String`s[0]s[0]
^^^^ string indices are ranges of `usize`
the type `str` cannot be indexed by `{integer}`
help: the trait `SliceIndex<str>` is not implemented for `{integer}`s + 'a's + 'a'
^ &str
s + 'a'
^^^ char
s + 'a'
^
cannot add `char` to `&str`s.chars()Chars(['h', 'o', 'w', ' ', 'a', 'r', 'e', ' ', 'y', 'o', 'u'])s.chars().nth(4)Some('a')s.push('c2')s.push('c2')
^^^^
character literal may only contain one codepoints.push('c2')
expected one of `.`, `;`, `?`, `}`, or an operator here
expected one of `.`, `;`, `?`, `}`, or an operator, found `evcxr_variable_store`s.push('c2')
^^^^
no method named `push` found for type `&str` in the current scopes.is_empty()falses.len()11String¶
let s1: String = "Hello World!";
s1let s1: String = "Hello World!";
^^^^^^^^^^^^^^ expected struct `String`, found `&str`
let s1: String = "Hello World!";
^^^^^^ expected due to this
mismatched types
help: try using a conversion method
"Hello World!".to_string()let mut s2: String = String::from("Hello World!");
s2"Hello World!"s2 + 'a's2 + 'a'
^^^ expected `&str`, found `char`
mismatched typess2.push('a')()s2"Hello World!a"Construct Strings¶
String::new¶
String::new creates an new empty string.
String::new()""String::with_capacity creates a new emtpy string with the given capacity.
let my_str = String::with_capacity(2);
my_str""my_str.capacity()2Cases of String¶
The
to_*casemethods return a new String object (mainly because changing the case of non-ASCII character might change the length of the string). Themake_ascii_*casemethods changes cases in place (as changing the case of ASCII characters won’t change the length of the string).to_*casemethods change the case of all characters whileto_ascii_*casemethods only change the case of ASCII characters and leave non-ASCII characters unchanged.
to_lowercase and to_uppercase¶
to_ascii_lowercase and to_ascii_uppercase¶
make_ascii_lowercase and make_ascii_upper¶
chars¶
contains¶
get¶
let s: String = String::from("Hello World!");
s.get(0..3)Some("Hel")let s: String = String::from("Hello World!");
let ss = s.get(0..3).unwrap().to_string();
ss"Hel"join¶
["a", "b"].join("")"ab"['a', 'b'].join("")['a', 'b'].join("")
^^^^ method not found in `[char; 2]`
no method named `join` found for array `[char; 2]` in the current scopevec!["a", "b"].join("")"ab"vec![String::from("a"), String::from("b")].join("")"ab"len¶
matches¶
An iterator over the disjoint matches of a pattern within the given string slice.
The pattern can be a &str, char, a slice of chars, or a function or closure that determines if a character matches.
"abcXXXabcYYYabc".matches("abc").collect::<Vec<_>>()["abc", "abc", "abc"]char::is_numeric('a')falsechar::is_numeric('1')true"1abc2abc3".matches(char::is_numeric).collect::<Vec<_>>()["1", "2", "3"]replace¶
parse (Convert String to Other Types)¶
Convert an integer to string.
let s = 123.to_string();
s"123"1.to_string()"1"Convert a string to bytes.
"1".as_bytes()[49]1.to_string().as_bytes()[49]1i32.to_be_bytes()[0, 0, 0, 1]Convert the string back to integer.
s.parse::<i32>()Ok(123)s.parse::<i32>().unwrap()123push¶
You cannot concatenate a char to a string using the + operator.
However,
you can use the String.push method to add a char to the end of a String.
push_str¶
is_empty¶
split¶
"".split(",").collect::<Vec<&str>>()[""]"".split(" ").collect::<Vec<&str>>()[""]"1,2,3".split(",")Split(SplitInternal { start: 0, end: 5, matcher: StrSearcher { haystack: "1,2,3", needle: ",", searcher: TwoWay(TwoWaySearcher { crit_pos: 0, crit_pos_back: 1, period: 1, byteset: 17592186044416, position: 0, end: 5, memory: 0, memory_back: 1 }) }, allow_trailing_empty: true, finished: false })let mut it = "1,2,3".split(",");
itSplit(SplitInternal { start: 0, end: 5, matcher: StrSearcher { haystack: "1,2,3", needle: ",", searcher: TwoWay(TwoWaySearcher { crit_pos: 0, crit_pos_back: 1, period: 1, byteset: 17592186044416, position: 0, end: 5, memory: 0, memory_back: 1 }) }, allow_trailing_empty: true, finished: false })it.next()Some("1")it.next()Some("2")it.next()Some("3")it.next()Nonelet v: Vec<&str> = "1,2,3".split(",").collect();
v["1", "2", "3"]v.capacity()4let v: Vec<i8> = "1,2,3".split(",").map(|x| x.parse::<i8>().unwrap()).collect();
v[1, 2, 3]v.capacity()8split_whitespace¶
"how are you".split_whitespace()SplitWhitespace { inner: Filter { iter: Split(SplitInternal { start: 0, end: 11, matcher: CharPredicateSearcher { haystack: "how are you", char_indices: CharIndices { front_offset: 0, iter: Chars { iter: Iter([104, 111, 119, 32, 97, 114, 101, 32, 121, 111, 117]) } } }, allow_trailing_empty: true, finished: false }) } }for word in "how are you".split_whitespace() {
println!("{}", word);
}how
are
you
()trim(&self) -> &str¶
Returns a string slice with leading and trailing whitespace removed.
" how\n".trim()"how"trim_end(&self) -> &str¶
Returns a string slice with trailing whitespace removed.
" how\n".trim_end()" how"trim_start(&self) -> &str¶
Returns a string slice with leading whitespace removed.
" how\n".trim_start()"how\n"with_capacity¶
let ss = String::with_capacity(3);
ss""Print Strings¶
You cannot use print an integer directly. Instead, you have to convert it to a String first.
It is suggested that you use
println!("{}", var);to print the variable to terminal so that you do not have to worry about its type.m
println!(5)format argument must be a string literalprintln!("{}", 5)5
()println!("My name is {} and I'm {}", "Ben", 34);My name is Ben and I'm 34
println!("{0} * {0} = {1}", 3, 9);3 * 3 = 9
println!("{x} * {x} = {y}", x=3, y=9);3 * 3 = 9
Placeholder Traits¶
println!("Binary: {v:b}, Hex: {v:x}, Octol: {v:o}", v = 64);Binary: 1000000, Hex: 40, Octol: 100
Print an Iterable¶
println!("{:?}", ("Hello", "World"));("Hello", "World")
The concat! Macro¶
Concatenates literals into a static string slice.
Concatenate a String and a Char¶
let mut my_str = String::from("Hello World");
my_str.push('!');
my_str"Hello World!"Concatenate Several Strings Together¶
The GitHub repo
dclong
Concatenate Strings in an Array/Vector¶
["how", "are", "you"].join(" ")"how are you"vec!["how", "are", "you"].join(" ")"how are you"Concatenate Strings in an Iterator¶
let v = vec!["how", "are", "you"];
v.into_iter().collect::<String>()"howareyou"let v = vec!["how", "are", "you"];
v.into_iter().collect::<String>()"howareyou"let arr = ["how", "are", "you"];
arr.into_iter().collect::<String>()arr.into_iter().collect::<String>()
^^^^^^^ value of type `String` cannot be built from `std::iter::Iterator<Item=&&str>`
a value of type `String` cannot be built from an iterator over elements of type `&&str`
help: the trait `FromIterator<&&str>` is not implemented for `String`let arr = ["how", "are", "you"];
arr.into_iter().copied().collect::<String>()"howareyou"let v = vec!["how", "are", "you"];
v.into_iter().intersperse(" ")v.into_iter().intersperse(" ")
^^^^^^^^^^^
use of unstable library feature 'iter_intersperse': recently addedIndexing a String¶
Indexing into a string is not available in Rust. The reason for this is that Rust strings are encoded in UTF-8 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, which is really bad if you need text processing) while char indexing is not free because UTF-8 is a variable-length encoding, so you have to traverse the entire string to find the required code point.
There are 2 ways to get chars out of a string.
First,
you can call the chars method which returns an iterator.
This ways is not efficient of course if you want random access.
Second,
you can get the underlying bytes representation of a string
by calling the as_bytes method
(which returns a byte slice &[u8].
You can then index the byte slice and convert a u8 variable to char
using the as keyword.
let s = String::from("how are you");
s[0]s[0]
^^^^ `String` cannot be indexed by `{integer}`
the type `String` cannot be indexed by `{integer}`
help: the trait `Index<{integer}>` is not implemented for `String`let s = String::from("how are you");
s.chars().next()Some('h')let s = String::from("how are you");
s.as_bytes()[2] as char'w'Slicing a String¶
"how are you"[..]"how are you""how are you"[..3]"how""how are you"[4..]"are you""how are you"[4..7]"are"