String
newIn Rust we often need to create new strings. We can use the new()
or from()
functions for this—or the to_owned()
function can be used on a literal.
String
referencesTo receive a str
reference, we can borrow a String
with the ampersand operator. This gives us string
data behind a reference that we cannot change.
For creating new Strings in Rust, it is best to start with a String
function like new()
or from()
. This often leads to the simplest code.
String::new()
and then call push_str
to append some data to the string
that was just allocated.String::from()
function to initialize a string
from a str
reference. The "cat" literal is a str
reference.to_owned()
on a literal to create a String
from it. This syntax is probably the least clear.fn main() { // Version 1: use new. let mut first = String::new(); first.push_str("cat"); println!("{first}"); // Version 2: use from. let second = String::from("cat"); println!("{second}"); // Version 3: use to_owned. let third = "cat".to_owned(); println!("{third}"); }cat cat cat
string
When we borrow a String
, we get a str
reference. Here the print_len()
function receives a str
reference, and we pass a String
to it with borrowing.
fn print_len(value: &str) { println!("LEN = {}", value.len()); } fn main() { let mut value = String::new(); value.push_str("abc"); // We can borrow the string to use it as a str reference. print_len(&value); }LEN = 3
String
cache performanceSuppose we want to allocate a short-lived temporary string
and use it for some reason. This could happen many times in a program.
String
new()
to allocate a new string
on each iteration of the benchmarked loop.RefCell
cache on the Example struct
, calling borrow_mut()
, and then reuse the existing String
.String
, even if we have to access it through a RefCell
.String
new()
, we must use the memory allocator. And this has significant overhead, even though Rust is not garbage-collected.use std::cell::*; use std::time::*; struct Example { cache: RefCell<String>, } fn main() { let ex = Example { cache: RefCell::new(String::new()), }; if let Ok(max) = "100000000".parse::<usize>() { // Version 1: use String new. let t0 = Instant::now(); for _ in 0..max { let mut temp = String::new(); temp.push('z'); temp.push_str("hello"); } println!("{} ms", t0.elapsed().as_millis()); // Version 2: use RefCell cache String. let t1 = Instant::now(); for _ in 0..max { let mut temp = ex.cache.borrow_mut(); temp.clear(); temp.push('z'); temp.push_str("hello"); } println!("{} ms", t1.elapsed().as_millis()); } }1299 ms String new 145 ms Borrow_mut, String clear
We reviewed the String::new()
, from()
, and to_owned
functions. We learned how to get a str
from a String
instance. And we benchmarked a String
cache, which could help performance.