I want to specialize &\'static str
from &\'a str
. Something like this:
use std::borrow::Cow;
struct MyString {
inner:
Rust 1.25.0 does not have specialization of any kind. If I'm reading the specialization RFC correctly, then lifetime specialization will not be supported even when the RFC is implemented:
A hard constraint in the design of the trait system is that dispatch cannot depend on lifetime information. In particular, we both cannot, and should not allow specialization based on lifetimes:
We can't, because when the compiler goes to actually generate code ("trans"), lifetime information has been erased -- so we'd have no idea what specializations would soundly apply.
We shouldn't, because lifetime inference is subtle and would often lead to counterintuitive results. For example, you could easily fail to get
'static
even if it applies, because inference is choosing the smallest lifetime that matches the other constraints.
(Emphasis mine)
There's some examples further in the link that indicate some of the concrete issues.
I recommend using a Cow
to handle the "owned or borrowed" case.
I write this answer after reading this duplicated post asking how to define a method/function that behaves differently when it is passed a static string or a non-static string.
This is not possible, so a workaround may be using a wrapper type to wrap the string argument in an enum
:
enum MyString {
Static(&'static str),
Heap(String),
}
fn bar(arg: &MyString) {
match arg {
&MyString::Static(ref name) => println!("my first pc was {}", name),
&MyString::Heap(ref name) => println!("I dont know {}", name),
}
}
fn main() {
let mut v = Vec::new();
let forever: &'static str = "zx-spectrum";
let local: &str = &"commodore64".to_string();
v.push(MyString::Static(forever));
// ERROR: try to insert 'a lifetime
// v.push(Mystring::Static(local));
v.push(MyString::Heap(local.to_string()));
v.push(MyString::Heap("muggle".to_string()));
bar(&v[0]);
bar(&v[1]);
}
MyString
stores a statically-allocated string literal as a &'static str
and all other strings as a String
.
As pointed in the comments below, the standard library provides a type that fits the borrowed/owned case: the smart pointer Cow.
The enum MyString
used in this example is just a specific enum for managing string types.
The only difference stems from a somewhat more specific naming of the enum and its variants related to the specific usage: MyString::Static("forever")
versus Cow::Borrowed("forever")
and MyString::Heap(str)
versus Cow::Owned(str)
.
Does this help improve mnemonics and code readability? I'm quite sure that this holds only for novices or occasional Rust programmers, not for seasoned Rustaceans.