简体   繁体   English

特质实施大小

[英]Trait implementing Sized

I know that traits and slices are unsized, ie it's not possible to know their size at compile time, eg any type may implement a trait, but that type may not be sized. 我知道特征和切片是未分类的,即在编译时不可能知道它们的大小,例如任何类型都可以实现特征,但是该类型可能没有大小。

Nevertheless, doesn't this example code mean that every type which implements trait Foo needs to implement Sized too? 不过,这个示例代码是不是意味着每个实现特性Foo类型都需要实现Sized呢?

trait Foo: Sized {}

struct Bar(i64);

impl Foo for Bar {}

If that's so, why doesn't this work? 如果是这样,为什么这不起作用?

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`

I want to provide to the consumer of the library a type (let's name it Bar ) and make it possible to convert to Bar from any other type which implements a particular trait (let's name it Foo ). 我想向库的使用者提供一个类型(让我们将其命名为Bar ),并且可以从实现特定特征的任何其他类型转换为Bar (让我们将其命名为Foo )。

I solved it by passing Foo by the reference instead of the value, but I'm not sure why the compiler complains if it's required for implementors to be Sized . 我通过引用传递Foo而不是值来解决它,但是我不确定为什么编译器会抱怨实现者需要Sized

Why doesn't it work? 为什么不起作用?

When you say that every Foo is Sized , you're kind of hiding the truth to yourself. 当你说每个Foo都是Sized ,你就是在向自己隐瞒真相。 Yes, every Foo is Sized but actually every type has a given size at some point. 是的,每个Foo都是Sized但实际上每种类型在某些时候都有给定的大小。 The real important information is that you're not saying how much this size is. 真正重要的信息是你没有说这个尺寸是多少。 Imagine if Bar(i64) is Foo , but Baz(i8) is Foo as well (they're both Sized , right?) which size do you determine Foo to be? 想象一下,如果Bar(i64)Foo ,但是Baz(i8)也是Foo (它们都是Sized ,对吗?)你确定Foo大小是多少? Is it 8- or 1-byte long? 是8字节还是1字节长? This question is asked by the compiler when it tries to generate the code for your function from(foo: Foo) . 当编译器尝试from(foo: Foo)生成函数代码时,会询问此问题。 Usually, Sized is rather used in a "maybe"-style with the syntax ?Sized , indicating that the type size might be unknown at compile time. 通常, Sized更适用于“可能”式的语法?Sized ,表示在编译时类型大小可能是未知的。

How to solve it? 怎么解决?

Typically you ditch the : Sized part, and use the following syntax, which is actually kind of a C++ template; 通常你抛弃: Sized部分,并使用以下语法,这实际上是一种C ++模板; it gives the compiler a sketch to write the actual code when given a concrete type with a given size. 当给定具有给定大小的具体类型时,它为编译器提供草图以编写实际代码。

trait Foo {}

struct Bar(i64);

impl Foo for Bar {}

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

(This will still error based on the fact that you cannot reimplement From because of the std crate , but it's not related to your original question.) (这将仍然错误基础上的事实,你不能重新实现From因的std ,但它没有涉及到你原来的问题。)

You could also use the reference trait object &Foo syntax in the argument to your function. 您还可以在函数的参数中使用引用特征对象&Foo语法。 This would transform your call from static dispatch to dynamic dispatch ( read more here ) but you can't do this here because the signature is imposed by the trait. 这会将您的调用从静态调度转换为动态调度( 在此处阅读更多内容 ),但您不能在此处执行此操作,因为签名是由特征强加的。

The Foo trait requires implementors to be Sized . Foo特性要求实现者的Sized It doesn't mean that Foo itself will have a size. 这并不意味着Foo本身会有一个大小。 You're misunderstanding the syntax the second code example and I'm therefore not sure what you're actually trying to do. 你误解了第二个代码示例的语法,因此我不确定你实际上要做什么。 Are you looking for this? 你在找这个吗?

impl From<i64> for Bar {
    fn from(val: i64) -> Bar {
        Bar(val)
    }
}

Or do you want a way to construct a Bar from any signed integer? 或者你想要一种从任何有符号整数构造一个Bar的方法?

We've got a XY problem here. 我们这里有一个XY问题

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

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