为什么这个特征中需要“Sized”界限?

2024-01-01

我有一个具有两个相关功能的特征:

trait WithConstructor: Sized {
    fn new_with_param(param: usize) -> Self;

    fn new() -> Self {
        Self::new_with_param(0)
    }
}

为什么第二种方法的默认实现(new())强迫我把Sized绑定在类型上?我认为这是因为堆栈指针操作,但我不确定。

如果编译器需要知道在堆栈上分配内存的大小, 为什么下面的例子不需要Sized for T?

struct SimpleStruct<T> {
    field: T,
}

fn main() {
    let s = SimpleStruct { field: 0u32 };
}

您可能已经知道,Rust 中的类型可以调整大小和取消大小。顾名思义,无大小类型没有编译器已知的存储该类型值所需的大小。例如,[u32]是一个未调整大小的数组u32s;因为元素的数量没有在任何地方指定,所以编译器不知道它的大小。另一个例子是裸特征对象类型,例如,Display,当它直接用作类型时:

let x: Display = ...;

在这种情况下,编译器不知道这里实际使用的是哪种类型,它被删除,因此它不知道这些类型的值的大小。上面的行无效 -如果不知道局部变量的大小,就无法创建局部变量(在堆栈上分配足够的字节),并且您无法将未调整大小的类型的值作为参数传递给函数或从函数返回它.

然而,可以通过指针使用未指定大小的类型,该指针可以携带附加信息 - 切片的可用数据的长度(&[u32])或指向虚拟表的指针(Box<SomeTrait>)。由于指针始终具有固定且已知的大小,因此它们可以存储在局部变量中并传递到函数或从函数返回。

给定任何具体类型,您始终可以判断它是否已调整大小或未调整大小。然而,对于泛型,出现了一个问题 - 某些类型参数是否具有大小?

fn generic_fn<T>(x: T) -> T { ... }

If T未调整大小,那么这样的函数定义是不正确的,因为您不能直接传递未调整大小的值。如果尺寸合适,那么一切就OK了。

在 Rust 中,所有泛型类型参数的大小都默认在任何地方 - 在函数、结构和特征中。他们有一个隐含的Sized边界;Sized是标记大小类型的特征:

fn generic_fn<T: Sized>(x: T) -> T { ... }

这是因为在绝大多数情况下,您希望调整通用参数的大小。然而,有时您想要选择退出尺寸,这可以通过?Sized bound:

fn generic_fn<T: ?Sized>(x: &T) -> u32 { ... }

Now generic_fn可以这样称呼generic_fn("abcde"), and T将被实例化为str这是未调整大小的,但没关系 - 该函数接受对T,所以没有什么不好的事情发生。

然而,在另一个地方,规模问题也很重要。 Rust 中的特征总是针对某种类型实现:

trait A {
    fn do_something(&self);
}

struct X;
impl A for X {
    fn do_something(&self) {}
}

然而,这只是为了方便和实用的目的所必需的。可以将特征定义为始终采用一种类型参数,并且不指定该特征所实现的类型:

// this is not actual Rust but some Rust-like language

trait A<T> {
    fn do_something(t: &T);
}

struct X;
impl A<X> {
    fn do_something(t: &X) {}
}

这就是 Haskell 类型类的工作方式,事实上,这就是在 Rust 中较低级别实际实现特征的方式。

Rust 中的每个特征都有一个隐式类型参数,称为Self,它指定实现此特征的类型。它始终在特征的主体中可用:

trait A {
    fn do_something(t: &Self);
}

这就是尺寸问题出现的地方。是个Self参数大小?

事实证明,不,SelfRust 中默认没有大小。每个特质都有一个隐含的?Sized绑定于Self。需要这样做的原因之一是因为有很多特征可以针对未调整大小的类型实现并且仍然有效。例如,任何仅包含仅接受和返回的方法的特征Self通过引用可以针对未确定大小的类型实现。您可以阅读有关动机的更多信息RFC 546 https://github.com/rust-lang/rfcs/blob/master/text/0546-Self-not-sized-by-default.md.

当您只定义特征及其方法的签名时,大小不是问题。由于这些定义中没有实际代码,因此编译器无法假设任何内容。但是,当您开始编写使用此特征的通用代码时,其中包括默认方法,因为它们采用隐式方法Self参数,您应该考虑尺寸。因为Self默认情况下没有调整大小,默认特征方法无法返回Self按值或按值将其作为参数。因此,您需要指定Self必须默认调整大小:

trait A: Sized { ... }

或者您可以指定只有在以下情况下才能调用方法Self尺寸为:

trait WithConstructor {
    fn new_with_param(param: usize) -> Self;

    fn new() -> Self
    where
        Self: Sized,
    {
        Self::new_with_param(0)
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么这个特征中需要“Sized”界限? 的相关文章

随机推荐

  • Asp.Net MVC 5 Owin Twitter Auth 抛出 401 异常

    我已经使用 Owin 中间件设置了 OAuth 身份验证 该中间件基于使用 个人帐户 身份验证启动新 Web 项目时创建的默认项目 我对其进行了一些调整 但 Facebook 和 Google 运行良好 但是 当我单击 twitter 按钮
  • Drupal 7:上传时重命名文件(通过文件字段)

    我正在寻找一种方法来重命名用户通过文件字段上传的文件 例如 使用以下命令重命名用户个人资料照片uniqid 我在 D6 找到了一个很好的解决方案Drupal 6 如何在上传时更改文件名 http www wesjones net home
  • django-tastypie - 如何通过关系实现多对多

    我正在为一个项目开发 API 并且通过 OrderProducts 建立订单 产品关系 如下所示 在目录 models py中 class Product models Model 按顺序 models py class Order mod
  • 寻找一些有趣的 C# 编程问题 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我厌倦了典型的 CRUD 编程类型应用程序 我想解决一些有趣的 不太难的 编程问题 有没有任何网站可以帮助我锻炼大脑 欧拉计划 htt
  • 如何使通用 SSR 的 Angular 应用程序使用 json 文件中的动态配置?

    我的任务是在应用程序启动期间从服务器上的 JSON 文件动态加载 Angular 应用程序的设置 特殊之处在于该应用程序使用 Universal 的服务器渲染 我尝试使用这种方法为浏览器执行此操作 https juristr com blo
  • 谁执行 unicode 标准化以及何时执行?

    根据JavaScript 权威指南 JavaScript 假定它正在解释的源代码已经标准化 并且不会尝试标准化标识符 字符串或正则表达式本身 Unicode 标准定义了所有字符的首选编码 并指定了将文本转换为适合比较的规范形式的规范化过程
  • 如何在 Rails 中将数组分配给 Mysql 列?

    我有一个 PostgreSQL 表 我想在 Rails 应用程序中将其转换为 MySql 最主要的是gateways列不会转换为 数组 列 在 schema rb 中看起来像这样 create table settings force ca
  • 为什么我们不能用右值 volatile int&& 初始化对 const int 的引用?

    我写了下面的例子 include
  • yacc shift-reduce 处理不明确的 lambda 语法

    我正在用 Yacc 用 Go 打包的语言 编写一种玩具语言的语法 由于以下伪问题 我遇到了预期的移位归约冲突 我必须将问题语法提炼为以下内容 start stmt list expr INT IDENT lambda expr 2 lamb
  • 指定不同的公共路径

    我的 Laravel 应用程序在私有文件夹中运行 我需要告诉 Laravel 公共路径是不同的 今天我将 Laravel 应用程序从 4 2 升级到 5 0 但我找不到在哪里指定公共路径因为 paths php 文件在 Laravel 5
  • Python create_task 在运行事件循环中不起作用

    我有一段简单的代码让我发疯了一段时间 我已经发帖了this https stackoverflow com questions 56350166 python event loop does not work properly with s
  • 使用javascript和jquery,用数组结构填充相关的选择框

    使用答案这个问题 https stackoverflow com questions 57522 javascript array with a mix of literals and arrays 我已经能够根据另一个选择框的选择来填充一
  • IntelliJ 下划线反斜杠

    我使用反斜杠作为我正在处理的序列化格式的转义字符 我将它作为常量 但 IntelliJ 强调它并以红色突出显示 悬停时 它不会给出错误消息或任何有关其不喜欢它的原因的信息 这是什么原因以及如何解决 IntelliJ 比我聪明 意识到我在正则
  • 将 python 列表转换为字典

    我正在尝试将我的列表转换为 python 中的字典 我有清单l l a b c d 我想将它转换为字典 d d a d b d c d d 我正在尝试 for i in range 0 len l d i 0 l i 但这行不通 谢谢 保持
  • 即使使用 -Ofast,Swift 的字典也很慢

    我正在使用本质上实现缓存Dictionary在斯威夫特 表现远远低于我的预期 我读过其他一些问题 例如这是关于数组排序的 https stackoverflow com questions 24101718 swift performanc
  • Backbonejs 与小胡子模板。

    我想使用带有小胡子模板的backbonejs 来做一个简单的应用程序 你能给我一个示例程序吗 新节点文件 var Person Backbone Model extend defaults name Guest Worker var Per
  • 为什么 Applicative 应该是 Monad 的超类?

    Given Applicative m Monad m gt mf m a gt b ma m a 这似乎被认为是一项法律 mf lt gt ma do f lt mf a lt ma return f a 或者更简洁地说 lt gt ap
  • 获取鼠标相对于饼图的位置(方程)

    我已经从一组数据创建了一个画布饼图 我现在尝试定位相对于饼图的鼠标位置 以检测正在悬停的数据部分 我快到了 但我被一个方程式困住了 我的逻辑运行良好 所以我认为这更像是一个数学问题 但会看看其他人对我的方法的看法 这是我的饼图和我正在使用的
  • Maven `pom.xml` 中 标签之间的区别[重复]

    这个问题在这里已经有答案了 配置我的时pom xml 我必须配置一个插件 我发现的是
  • 为什么这个特征中需要“Sized”界限?

    我有一个具有两个相关功能的特征 trait WithConstructor Sized fn new with param param usize gt Self fn new gt Self Self new with param 0 为