I would like to give an example where you cannot change a String
(at least not from outside a module) but where it may be necessary to use a String
rather than &'static str
:
mod m {
pub struct Person {
name: String,
age: u16,
}
impl Person {
pub fn new(name: String, age: u16) -> Person {
Person { name, age }
}
pub fn increase_age(&mut self) {
self.age += 1;
}
pub fn name(&self) -> &str {
&self.name
}
pub fn age(&self) -> u16 {
self.age
}
}
}
use m::Person;
fn main() {
let mut p = Person::new(String::from("Johnny"), 59);
p.increase_age();
// Note we cannot change Johnny's name here without creating a new `Person`.
println!("{} is {} years old now.", p.name(), p.age());
}
(Playground)
Output:
Johnny is 60 years old now.
In the given example above, m::String::new
expects the name as a String
(and stores it as String
). This makes sense if we sometimes read strings from I/O (e.g. file system, text console, or network). Yet we can set the name to a preset constant ("Johnny") in that example. But when we call m::String::new
, we have to convert "Johnny"
(which is a &str
) to a String
as that's what we store (and which is what the new
function expects to get).
If we would instead have written:
pub struct Person {
name: &'static str,
age: u16,
}
then we would only be able to store string literals, but not arbitrary input from the network or an external database, for example.
If we would have written:
pub struct Person<'a> {
name: &'a str,
age: u16,
}
then we introduce a lifetime argument for Person
, which means that the Person<'a>
can only exist as long as the reference to that stored string is valid. Depending on the application case, this can be very unhandy.