This example creates strings in four different ways that all work with the print_me function. The key to making this all work is passing values by reference. Rather than passing owned_string as a String to print_me, we instead pass it as &String. When the compiler sees a &String being passed to a function that takes &str, it coerces the &String into a &str. This same coercion takes places for the reference counted and atomically referenced counted strings. The string variable is already a reference, so no need to use a & when calling print_me(string). Knowing this, we no longer need to have .to_string() calls littering our code.
fn print_me(msg: &str) { println!("msg = {}", msg); }
fn main() {
let string = "hello world";
print_me(string);
let owned_string = "hello world".to_string(); // or String::from_str("hello world")
print_me(&owned_string);
let counted_string = std::rc::Rc::new("hello world".to_string());
print_me(&counted_string);
let atomically_counted_string = std::sync::Arc::new("hello world".to_string());
print_me(&atomically_counted_string);
}