String new ExamplesUse String new to create a string, allocating it on the heap. Use from, and reuse existing strings for performance.
This page was last reviewed on Jul 15, 2023.
String new. In 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 references. To receive a str reference, we can borrow a String with the "&" operator. This gives us string data behind a reference that we cannot change.
New example. 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.
Version 1 We use new() and then call push_str to append some data to the string that was just allocated.
Version 2 We use the String from() function to initialize a string from a str reference. The "cat" literal is a str reference.
Version 3 We use 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
Borrow string. When we borrow a String, we get a str reference. Here the print_len() function receives a &str, 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 performance. Suppose we want to allocate a short-lived temporary string and use it for some reason. This could happen many times in a program.
Version 1 We use String new() to allocate a new string on each iteration of the benchmarked loop.
Version 2 We access the RefCell cache on the Example struct, calling borrow_mut(), and then reuse the existing String.
Rc, RefCell
Result It is nearly 10 times faster to reuse an already-allocated String, even if we have to access it through a RefCell.
Info When we call 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
Summary. 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.
Dot Net Perls is a collection of tested code examples. Pages are continually updated to stay current, with code correctness a top priority.
Sam Allen is passionate about computer languages. In the past, his work has been recommended by Apple and Microsoft and he has studied computers at a selective university in the United States.
This page was last updated on Jul 15, 2023 (edit).
© 2007-2023 Sam Allen.