debugrustMajor
What does “`str` does not have a constant size known at compile-time” mean, and what's the simplest way to fix it?
Viewed 0 times
constantknownfixcompilehaveandtimestrthedoes
Problem
I'm trying to manipulate a string derived from a function parameter and then return the result of that manipulation:
On building, I get this error:
What's wrong here, and what's the simplest way to fix it?
fn main() {
let a: [u8; 3] = [0, 1, 2];
for i in a.iter() {
println!("{}", choose("abc", *i));
}
}
fn choose(s: &str, pad: u8) -> String {
let c = match pad {
0 => ["000000000000000", s].join("")[s.len()..],
1 => [s, "000000000000000"].join("")[..16],
_ => ["00", s, "0000000000000"].join("")[..16],
};
c.to_string()
}On building, I get this error:
error[E0277]: the trait bound str: std::marker::Sized is not satisfied
--> src\main.rs:9:9
|
9 | let c = match pad {
| ^ str does not have a constant size known at compile-time
|
= help: the trait std::marker::Sized is not implemented for str
= note: all local variables must have a statically known size
What's wrong here, and what's the simplest way to fix it?
Solution
TL;DR Don't use
The issue can be simplified to this:
You are attempting to slice a
In your broader example, you are also running into the fact that you are creating an allocated
One potential fix is to store the created
Editorially, there's probably more efficient ways of writing this function. The formatting machinery has options for padding strings. You might even be able to just truncate the string returned from
What it means is harder to explain succinctly. Rust has a number of types that are unsized. The most prevalent ones are
Because these types don't have a size, they cannot be stored in a variable on the stack — the compiler wouldn't know how much stack space to reserve for them! That's the essence of the error message.
See also:
str, use &str. The reference is important.The issue can be simplified to this:
fn main() {
let demo = "demo"[..];
}You are attempting to slice a
&str (but the same would happen for a String, &[T], Vec, etc.), but have not taken a reference to the result. This means that the type of demo would be str. To fix it, add an &:let demo = &"demo"[..];In your broader example, you are also running into the fact that you are creating an allocated
String inside of the match statement (via join) and then attempting to return a reference to it. This is disallowed because the String will be dropped at the end of the match, invalidating any references. In another language, this could lead to memory unsafety.One potential fix is to store the created
String for the duration of the function, preventing its deallocation until after the new string is created:fn choose(s: &str, pad: u8) -> String {
let tmp;
match pad {
0 => {
tmp = ["000000000000000", s].join("");
&tmp[s.len()..]
}
1 => {
tmp = [s, "000000000000000"].join("");
&tmp[..16]
}
_ => {
tmp = ["00", s, "0000000000000"].join("");
&tmp[..16]
}
}.to_string()
}Editorially, there's probably more efficient ways of writing this function. The formatting machinery has options for padding strings. You might even be able to just truncate the string returned from
join without creating a new one.What it means is harder to explain succinctly. Rust has a number of types that are unsized. The most prevalent ones are
str and [T]. Contrast these types to how you normally see them used: &str or &[T]. You might even see them as Box or Arc. The commonality is that they are always used behind a reference of some kind.Because these types don't have a size, they cannot be stored in a variable on the stack — the compiler wouldn't know how much stack space to reserve for them! That's the essence of the error message.
See also:
- What is the return type of the indexing operation?
- Return local String as a slice (&str)
- Why your first FizzBuzz implementation may not work
Code Snippets
fn main() {
let demo = "demo"[..];
}let demo = &"demo"[..];fn choose(s: &str, pad: u8) -> String {
let tmp;
match pad {
0 => {
tmp = ["000000000000000", s].join("");
&tmp[s.len()..]
}
1 => {
tmp = [s, "000000000000000"].join("");
&tmp[..16]
}
_ => {
tmp = ["00", s, "0000000000000"].join("");
&tmp[..16]
}
}.to_string()
}Context
Stack Overflow Q#49393462, score: 65
Revisions (0)
No revisions yet.