为什么在 trait 方法声明中允许使用 unsized 类型?

Ibr*_*med 8 rust

为什么在 trait 方法声明中允许使用 unsized 类型?例如,此代码编译:

trait Blah {
    fn blah(&self, input: [u8]) -> dyn Display;
}
Run Code Online (Sandbox Code Playgroud)

但实施Blah是不可能的:

impl Blah for Foo {
    fn blah(&self, input: [u8]) -> dyn Display {
        "".to_string()
    }
} 
// error[E0277]: the size for values of type `(dyn std::fmt::Display + 'static)` cannot be known at compilation time
// error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
Run Code Online (Sandbox Code Playgroud)

给出blah默认实现也是不可能的:

trait Blah {
    fn blah(&self, input: dyn Display) -> dyn Display { "".to_string() }
}
// error[E0277]: the size for values of type `(dyn std::fmt::Display + 'static)` cannot be known at compilation time
Run Code Online (Sandbox Code Playgroud)

也不允许嵌套的 unsized 类型。这种不一致让我认为这是一个编译器错误:

trait Blah {
    fn blah(&self, input: [str]) -> dyn Display;
}
// error[E0277]: the size for values of type `str` cannot be known at compilation time
Run Code Online (Sandbox Code Playgroud)

我发现了几个旧的 GitHub 问题,声称这种行为是故意的,但我找不到原因。为什么这是故意行为?如果实现这种性质的特征是不可能的,为什么编译器不在特征声明中捕获它?

tre*_*tcl 6

我相信这里有两个不同的问题:未调整大小的函数参数和未调整大小的返回类型。

\n

未调整大小的参数类型

\n

未调整大小的函数参数实际上在 nightly Rust 中实现并可用feature(unsized_fn_params)。这很可能会在某个时候稳定下来,然后就有可能实现这样的特征:

\n
trait Crab {\n    fn pinch(&self, data: str);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

目前在稳定的 Rust 中无法实现。

\n

事实上,标准库使用此功能来实现FnOnce()forBox<dyn FnOnce()>,这需要移入方法*selfcall_once。由于FnOnce(某种)外部可见\xc2\xb9,并且std始终允许使用不稳定的功能,因此可能没有任何方法可以在unsized_fn_params不允许特征函数拥有它们(稳定)的情况下实现(夜间)。然而,这只是猜测。

\n

另请参阅如何在 Rust 中按值传递装箱特征对象?

\n

未指定大小的返回类型

\n

顾名思义,unsized_fn_params只影响参数;unsized_locals即使在(更广泛、更宽松、不太完整的功能)下,仍然不允许未调整大小的返回值。因此,允许的论点-> dyn Display远没有那么令人信服,并且有充分的理由表明这是一个实际的错误,或者至少值得一提。

\n

我相信其中的“故意”部分实际上仅适用于参数类型,并且包含返回类型是一个意外。

\n
\n

\xc2\xb9 这些Fn特征很特殊,因为在稳定中它们只能与Fn(...)语法一起使用,而不是与 一起Fn<Args>使用,但在约束和特征对象中仍然有效。

\n