How to match against a &'static str in Rust - rust

I am a Rust beginner and I can't solve this type problem. I have tried replacing &name with name, but the error "pattern &_ not covered" occurred.
fn get_project(name: &'static str) {
match &name {
"hi" => {},
}
}
fn main() {
let project = get_project("hi");
}
Compiler error:
error[E0308]: mismatched types
--> <anon>:3:9
|
3 | "hi" => {},
| ^^^^ expected &str, found str
|
= note: expected type `&&str`
= note: found type `&'static str`

String literals – like "hi" – have the type &'static str. So if you already have a &str, you don't need to add the &:
fn get_project(name: &str) {
match name {
"hi" => {},
_ => {}, // matches have to be exhaustive
}
}
I also added a default case, because matches in Rust need to be exhaustive: they need to cover all possible cases.
Maybe you noticed, that I also removed the 'static from the argument list. If you want to read about some lifetime stuff, go ahead. Else, stop reading here, because it's possibly confusing and not that important in this case.
In this function there is no need to restrict the lifetime of the given argument to 'static. Maybe you also want to pass in string slices that are borrowed from a String:
let user_input = read_user_input(); // type `String`
get_project(&input);
The code above only works when you remove the 'static from the argument. Once removed, the function is equivalent to:
fn get_project<'a>(name: &'a str) { ... }
This means that the function is generic over a lifetime 'a. The function says: given any lifetime 'a, you can give me a string with said lifetime and I am able to do my thing. Which is true. If the function wouldn't be able to do it for any lifetime, the compiler would complain ;-)

In your example, name doesn't need to have a static lifetime. Because you only use name inside your function, name doesn't need to have an extended lifetime. Check out the strings chapter of The Rust Programming Language. To match a &str with a &'static str you don't need &, just the variable itself is enough.
pub fn get_project(name: &str) {
match name {
"hi" => println!("I found hi!"),
_ => println!("Nothing match"),
}
}
fn main() {
get_project("hi");
get_project("42");
}

Related

Taking ownership of a &String without copying

Context
Link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9a9ffa99023735f4fbedec09e1c7ac55
Here's a contrived repro of what I'm running into
fn main() {
let mut s = String::from("Hello World");
example(&mut s);
}
fn example(s: &mut str) -> Option<String> {
other_func(Some(s.to_owned()))
// other random mutable stuff happens
}
fn other_func(s: Option<String>) {
match s {
Some(ref s) => other_func2(*s),
None => panic!()
}
}
fn other_func2(s: String) {
println!("{}", &s)
}
and the error
Compiling playground v0.0.1 (/playground)
error[E0507]: cannot move out of `*s` which is behind a shared reference
--> src/main.rs:12:36
|
12 | Some(ref s) => other_func2(*s),
| ^^ move occurs because `*s` has type `String`, which does not implement the `Copy` trait
Question
In the following code, why can't I deference the &String without having to do some sort of clone/copy? i.e. this doesn't work
fn other_func(s: Option<String>) {
match s {
Some(ref s) => other_func2(*s),
None => panic!()
}
}
but it works if I replace *s with s.to_owned()/s.to_string()/s.clone()
As an aside, I understand this can probably be solved by refactoring to use &str, but I'm specifically interested in turning &String -> String
Why would the compiler allow you to?
s is &String. And you cannot get a String from a &String without cloning. That's obvious.
And the fact that it was created from an owned String? The compiler doesn't care, and it is right. This is not different from the following code:
let s: String = ...;
let r: &String = ...;
let s2: String = *r; // Error
Which is in turn not different from the following code, for instance, as far as the compiler is concerned:
let r: &String = ...;
let s: String = *s;
And we no longer have an owned string at the beginning. In general, the compiler doesn't track data flow. And rightfully so - when it type-checks the move it doesn't even can confirm that this reference isn't aliased. Or that the owned value is not used anymore. References are just references, they give you no right to drop the value.
Changing that will not be feasible in the general case (for example, the compiler will have to track data flow across function calls), and will require some form of manual annotation to say "this value is mine". And you already have such annotation - use an owned value, String, instead of &String: this is exactly what it's about.

How to do different things if a value is or is not valid for the 'static lifetime? [duplicate]

I want to specialize &'static str from &'a str:
use std::borrow::Cow;
struct MyString {
inner: Cow<'static, str>,
}
impl From<&'static str> for MyString {
fn from(x: &'static str) -> Self {
MyString {
inner: Cow::Borrowed(x),
}
}
}
impl<T: Into<String>> From<T> for MyString {
fn from(x: T) -> Self {
MyString {
inner: Cow::Owned(x.into()),
}
}
}
fn main() {
match MyString::from("foo").inner {
Cow::Borrowed(..) => (),
_ => {
panic!();
}
}
let s = String::from("bar");
match MyString::from(s.as_ref()).inner {
Cow::Owned(..) => (),
_ => {
panic!();
}
}
match MyString::from(String::from("qux")).inner {
Cow::Owned(..) => (),
_ => {
panic!();
}
}
}
The gist is that MyString stores a statically-allocated string literal as a &'static str and all other strings as a String. This allows MyString to avoid having a lifetime parameter—i.e., MyString<'a>, which is critical for my API, all while allowing the caller to pass in any kind of string and have MyString automatically do the correct thing.
The problem is that the code doesn't compile:
error[E0119]: conflicting implementations of trait `std::convert::From<&'static str>` for type `MyString`:
--> src/main.rs:15:1
|
7 | impl From<&'static str> for MyString {
| ------------------------------------ first implementation here
...
15 | impl<T: Into<String>> From<T> for MyString {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyString`
Is there any trick that allows me to do what I want? If not, is lifetime specialization something that Rust will ever support?
Rust 1.51.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.

Rust: Why passing unused (_) parameter to function changes the outcome

Why below snippet errors out
fn print() -> &str
{
let name2 = "blah";
return &name2;
}
fn main() {
let x = print();
println!("{}", x);
}
but not this
fn print(_: &str) -> &str
{
let name2 = "blah";
return &name2;
}
fn main()
{
let x = print("");
println!("{}", x);
}
The only difference is the additional parameter which is ignored in the last case
The error message tells you quite clearly why the first snippet fails:
1 | fn print() -> &str
| ^ expected named lifetime parameter
you're returning a reference, references must have a lifetime to indicate their validity. You don't provide a lifetime and rustc's rules don't provide any either, so the compilation fails.
In the second snippet, you pass in a reference. Following lifetime elision:
If there is exactly one input lifetime position (elided or not), that lifetime is assigned to all elided output lifetimes.
rustc will use the input lifetime for the output, hence the second snippet is in essence
fn print(_: &'a str) -> &'a str
Since a string literal has lifetime 'static, it can be "cast down" to any lifetime (since they're all shorter), therefore returning name2 which is an &'static str does not break the contract: it will be valid for whatever the caller provides and wants.
In the first case, the declaration is missing the lifetime specifier.
You could fix this declaration with the lifetime you use:
fn print() -> &'static str {
let name2 = "blah";
return &name2;
}
In the second one, you're using implicit lifetimes (with Rust Edition 2018).
Implicit lifetimes really means the lifetime of the function parameter is the lifetime on output. It is thus specified.
What you're implicitly declaring is this:
fn print<'a>(_: &'a str) -> &'a str {
let name2 = "blah";
return &name2;
}
It "works" but only because both the argument given and the implementations are based on static lifetime. Otherwise you wouldn't be able to call it. It thus adds really nothing over the first fixed version.
more on implicit anonymous lifetimes

Different implementations for static and non-static arguments [duplicate]

I want to specialize &'static str from &'a str:
use std::borrow::Cow;
struct MyString {
inner: Cow<'static, str>,
}
impl From<&'static str> for MyString {
fn from(x: &'static str) -> Self {
MyString {
inner: Cow::Borrowed(x),
}
}
}
impl<T: Into<String>> From<T> for MyString {
fn from(x: T) -> Self {
MyString {
inner: Cow::Owned(x.into()),
}
}
}
fn main() {
match MyString::from("foo").inner {
Cow::Borrowed(..) => (),
_ => {
panic!();
}
}
let s = String::from("bar");
match MyString::from(s.as_ref()).inner {
Cow::Owned(..) => (),
_ => {
panic!();
}
}
match MyString::from(String::from("qux")).inner {
Cow::Owned(..) => (),
_ => {
panic!();
}
}
}
The gist is that MyString stores a statically-allocated string literal as a &'static str and all other strings as a String. This allows MyString to avoid having a lifetime parameter—i.e., MyString<'a>, which is critical for my API, all while allowing the caller to pass in any kind of string and have MyString automatically do the correct thing.
The problem is that the code doesn't compile:
error[E0119]: conflicting implementations of trait `std::convert::From<&'static str>` for type `MyString`:
--> src/main.rs:15:1
|
7 | impl From<&'static str> for MyString {
| ------------------------------------ first implementation here
...
15 | impl<T: Into<String>> From<T> for MyString {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyString`
Is there any trick that allows me to do what I want? If not, is lifetime specialization something that Rust will ever support?
Rust 1.51.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.

Is it possible to specialize on a static lifetime?

I want to specialize &'static str from &'a str:
use std::borrow::Cow;
struct MyString {
inner: Cow<'static, str>,
}
impl From<&'static str> for MyString {
fn from(x: &'static str) -> Self {
MyString {
inner: Cow::Borrowed(x),
}
}
}
impl<T: Into<String>> From<T> for MyString {
fn from(x: T) -> Self {
MyString {
inner: Cow::Owned(x.into()),
}
}
}
fn main() {
match MyString::from("foo").inner {
Cow::Borrowed(..) => (),
_ => {
panic!();
}
}
let s = String::from("bar");
match MyString::from(s.as_ref()).inner {
Cow::Owned(..) => (),
_ => {
panic!();
}
}
match MyString::from(String::from("qux")).inner {
Cow::Owned(..) => (),
_ => {
panic!();
}
}
}
The gist is that MyString stores a statically-allocated string literal as a &'static str and all other strings as a String. This allows MyString to avoid having a lifetime parameter—i.e., MyString<'a>, which is critical for my API, all while allowing the caller to pass in any kind of string and have MyString automatically do the correct thing.
The problem is that the code doesn't compile:
error[E0119]: conflicting implementations of trait `std::convert::From<&'static str>` for type `MyString`:
--> src/main.rs:15:1
|
7 | impl From<&'static str> for MyString {
| ------------------------------------ first implementation here
...
15 | impl<T: Into<String>> From<T> for MyString {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyString`
Is there any trick that allows me to do what I want? If not, is lifetime specialization something that Rust will ever support?
Rust 1.51.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.

Resources