简体   繁体   English

“`str` 在编译时没有已知的恒定大小”是什么意思,修复它的最简单方法是什么?

[英]What does “`str` does not have a constant size known at compile-time” mean, and what's the simplest way to fix it?

I'm trying to manipulate a string derived from a function parameter and then return the result of that manipulation:我正在尝试操作从函数参数派生的字符串,然后返回该操作的结果:

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?这里出了什么问题,解决它的最简单方法是什么?

TL;DR Don't use str , use &str . TL;DR不要使用str ,使用&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<T> , etc.), but have not taken a reference to the result.您正在尝试对&str进行切片(但对于String&[T]Vec<T>等也会发生同样的情况),但没有引用结果。 This means that the type of demo would be str .这意味着demo的类型将是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.在您更广泛的示例中,您还遇到了这样一个事实,即您正在match语句(通过join )中创建分配的String ,然后尝试返回对它的引用。 This is disallowed because the String will be dropped at the end of the match , invalidating any references.这是不允许的,因为String将在match结束时被删除,从而使任何引用无效。 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:一种可能的解决方法是在函数执行期间存储创建的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()
}

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.您甚至可以截断从join返回的字符串,而无需创建新字符串。


What it means is harder to explain succinctly.它的含义很难简洁地解释。 Rust has a number of types that are unsized . Rust 有许多类型是unsized的。 The most prevalent ones are str and [T] .最流行的是str[T] Contrast these types to how you normally see them used: &str or &[T] .将这些类型与您通常看到的使用方式进行对比: &str&[T] You might even see them as Box<str> or Arc<[T]> .您甚至可以将它们视为Box<str>Arc<[T]> 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:也可以看看:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM