我正在尝试操作从函数参数派生的字符串,然后返回该操作的结果:
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()
}
在构建时,我收到此错误:
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
这里有什么问题,解决问题的最简单方法是什么?
答案 0 :(得分:9)
TL; DR 请勿使用str
,请使用&str
。参考很重要。
问题可以简化为:
fn main() {
let demo = "demo"[..];
}
您正在尝试对&str
进行切片(但对于String
,&[T]
,Vec<T>
等也会发生同样的情况,但尚未参考结果。这意味着demo
的类型将为str
。要解决此问题,请添加&
:
let demo = &"demo"[..];
在更广泛的示例中,您还遇到了这样一个事实:您正在String
语句中创建一个已分配的match
(通过join
),然后尝试返回一个引用它。这是不允许的,因为String
将在match
的末尾被删除,从而使任何引用无效。用另一种语言,这可能导致记忆不安全。
一个可能的解决方法是在函数持续时间内存储创建的String
,防止在创建新字符串之前将其释放:
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()
}
编辑,可能有更有效的方式来编写这个功能。 formatting machinery具有填充字符串的选项。您甚至可以截断从join
返回的字符串,而无需创建新字符串。
这意味着更难以简洁地解释。 Rust有许多类型 unsized 。最流行的是str
和[T]
。将这些类型与您通常看到它们的使用方式进行对比:&str
或&[T]
。您甚至可能会将其视为Box<str>
或Arc<[T]>
。通用性是它们总是在某种参考之后使用。
因为这些类型没有大小,所以它们不能存储在堆栈中的变量中 - 编译器不知道要为它们保留多少堆栈空间!这是错误信息的本质。
另见: