rust - 特征实现大小

标签 rust

我知道 traits 和 slices 是没有大小的,即在编译时不可能知道它们的大小,例如任何类型都可以实现特征,但该类型可能无法确定大小。

然而,这个示例代码是否意味着每个实现特征 Foo 的类型也需要实现 Sized

trait Foo: Sized {}

struct Bar(i64);

impl Foo for Bar {}

如果是这样,为什么这行不通?

impl From<Foo> for Bar {
    fn from(foo: Foo) -> Bar {
        Bar(64)
    }
}
error[E0277]: the trait bound `Foo + 'static: std::marker::Sized` is not satisfied
 --> src/main.rs:7:6
  |
7 | impl From<Foo> for Bar {
  |      ^^^^^^^^^ `Foo + 'static` does not have a constant size known at compile-time
  |
  = help: the trait `std::marker::Sized` is not implemented for `Foo + 'static`

我想为库的使用者提供一个类型(我们将其命名为 Bar),并可以从任何其他实现特定特征(我们将其命名为 Foo)。

我通过引用而不是值传递 Foo 解决了这个问题,但我不确定如果实现者需要 Sized 编译器为什么会提示。

最佳答案

为什么不起作用?

当您说每个 Foo 都是 Sized 时,您是在隐瞒真相。是的,每个 Foo 都是 Sized 但实际上每个类型在某个时候都有给定的大小。真正重要的信息是你没有说这个尺寸是多少。想象一下,如果 Bar(i64)Foo,但是 Baz(i8) 也是 Foo(它们是Sized,对吗?)你确定 Foo 的大小是多少?它是 8 字节还是 1 字节长?编译器在尝试为您的函数 from(foo: Foo) 生成代码时会询问此问题。通常,Sized 以“可能”的形式使用,语法为 ?Sized,表明类型大小在编译时可能是未知的。

如何解决?

通常您会放弃 : Sized 部分,并使用以下语法,这实际上是一种 C++ 模板;当给定具有给定大小的具体类型时,它为编译器提供了编写实际代码的草图。

trait Foo {}

struct Bar(i64);

impl Foo for Bar {}

impl<F: Foo> From<F> for Bar {
    fn from(foo: F) -> Bar {
        Bar(64)
    }
}

(这将 still error 基于 the fact that you cannot reimplement From because of the std crate ,但它与您的原始问题无关。)

您还可以在函数的参数中使用引用特征对象 &Foo 语法。这会将您的调用从静态分派(dispatch)转换为动态分派(dispatch) (read more here),但您不能在此处执行此操作,因为签名是由特征强加的。

关于rust - 特征实现大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31515921/

相关文章:

rust - 如果您只是将数据视为字节,那么使用 Rust 的 memmap 是否安全?

rust - 将 Cargo 与自定义链接器一起使用

rust - 通过 HashMap::Entry 进行模式匹配时出现 "ambiguous associated type"错误(错误代码 E0223)

rust - 名为 "transmute"的 Rust 内在函数实际上在哪里实现?

rust - 选项<Receiver> 在上一次循环迭代中移动

rust - 解构一个值以访问属性或使用它们的名称哪个更好?

generics - 类型参数不受 impl 特征、自身类型或谓词的约束

rust - Write::write_fmt 在裸机上导致页面错误

rust - 迭代递归结构时无法获取可变引用 : cannot borrow as mutable more than once at a time

asynchronous - 如何在异步函数调用的闭包内部延迟执行?