本文介绍了为什么在 trait 中返回 `Self` 有效,但返回 `Option<Self>` 需要 `Sized`?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个特征定义编译得很好:

This trait definition compiles fine:

trait Works {
    fn foo() -> Self;
}

然而,这确实会导致错误:

This, however, does lead to an error:

trait Errors {
    fn foo() -> Option<Self>;
}
error[E0277]: the size for values of type `Self` cannot be known at compilation time
 --> src/lib.rs:6:5
  |
6 |     fn foo() -> Option<Self>;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
  |
  = help: the trait `std::marker::Sized` is not implemented for `Self`
  = note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
  = help: consider adding a `where Self: std::marker::Sized` bound
  = note: required by `std::option::Option`

使用 : Sized 超特征绑定,它可以工作.

With the : Sized supertrait bound, it works.

我知道traits中的Self类型不会自动绑定到Sized.而且我知道 Option 不能返回(通过堆栈),除非它被调整(反过来,这需要 Self 被调整).但是,对于 Self 作为返回类型也是如此,对吧?除非确定大小,否则它也无法存储在堆栈中.

I know that the Self type in traits is not automatically bound to be Sized. And I understand that Option<Self> cannot be returned (via the stack) unless it is sized (which, in turn, requires Self to be sized). However, the same would go for Self as return type, right? It also cannot be stored on the stack unless it's sized.

为什么第一个特征定义没有触发那个错误?

(这个问题是相关,但它没有回答我的确切问题——除非我不明白.)

(This question is related, but it doesn't answer my exact question – unless I didn't understand it.)

推荐答案

这里进行了两组检查,这就是为什么差异看起来令人困惑的原因.

There are two sets of checks happening here, which is why the difference appears confusing.

  1. 检查函数签名中的每种类型的有效性.Option 本质上需要 T: Sized.不需要 Sized 的返回类型很好:

  1. Each type in the function signature is checked for validity. Option inherently requires T: Sized. A return type that doesn't require Sized is fine:

trait Works {
    fn foo() -> Box<Self>;
}

现有答案很好地涵盖了这一点.

任何带有主体的函数也会检查所有参数是否都是大小.没有主体的特征函数不应用此检查.

Any function with a body also checks that all of the parameters are Sized. Trait functions without a body do not have this check applied.

为什么这很有用?允许在 trait 方法中使用 unsized 类型是允许 by-value trait objects 的关键部分,这是一个非常有用的特性.例如,FnOnce 不要求 SelfSized:

Why is this useful? Allowing unsized types to be used in trait methods is a key part of allowing by-value trait objects, a very useful feature. For example, FnOnce does not require that Self be Sized:

pub trait FnOnce<Args> {
    type Output;
    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
fn call_it(f: Box<dyn FnOnce() -> i32>) -> i32 {
    f()
}

fn main() {
    println!("{}", call_it(Box::new(|| 42)));
}

非常感谢 pnkfelix 和 nikomatsakis 回答了我关于这个主题的问题.

这篇关于为什么在 trait 中返回 `Self` 有效,但返回 `Option<Self>` 需要 `Sized`?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 05:33