One option is to declare the name member as an enum that can either contain a String or an &'static str:
enum Name {
Static(&'static str),
Owned(String),
}
struct Class {
name: Name,
// ...
}
The class can then provide appropriate constructors (there will have to be two) and a get_name() method for accessing the name as string slice:
impl Class {
pub fn new_from_str(name: &'static str) -> Class {
Class { name: Name::Static(name) }
}
pub fn new_from_owned(name: String) -> Class {
Class { name: Name::Owned(name) }
}
pub fn get_name(&self) -> &str {
match self.name {
Name::Owned(ref s) => s.as_str(),
Name::Static(s) => s,
}
}
}
fn main() {
let c1 = Class::new_from_str("foo");
let c2 = Class::new_from_owned("foo".to_string());
println!("{} {}", c1.get_name(), c2.get_name());
}
The other option is to use the Cow type provided by the standard library for this purpose:
use std::borrow::Cow;
struct Class {
name: Cow<'static, str>,
}
Since Cow implements the Into trait, the constructor can now be written as a single generic function:
pub fn new<T>(name: T) -> Class
where T: Into<Cow<'static, str>> {
Class { name: name.into() }
}
Cow also implements the Deref trait, allowing get_name() to be written as:
pub fn get_name(&self) -> &str {
return &self.name;
}
In both cases the name member will equal the size of the larger variant plus the space taken by the discriminator. As String is the larger type here, and it takes up three pointer sizes (the string contents is allocated separately and doesn't count), Name will take four pointer sizes in total. In case of explicit enum, the member can be made smaller still by boxing the string:
enum Name {
Static(&'static str),
Owned(Box<String>),
}
This will cut down the size of Name to three pointer sizes, of which one slot is used for the discriminator and the remaining two for the string slice. The downside is that it requires an additional allocation and indirection for the owned-string case - but it might still pay off if the majority of your class names come from static string slices.
Cow? Feel free to write an answer about this, if it helps...