代数数据类型的特征

2024-04-17

我无法理解有关代数数据类型特征的规则。 这是一个简化的示例:

use std::rc::Rc;
use std::cell::RefCell;

trait Quack {
    fn quack(&self);
}

struct Duck;

impl Quack for Duck {
    fn quack(&self) { println!("Quack!"); }
}

fn main() {
    let mut pond: Vec<Box<Quack>> = Vec::new();
    let duck: Box<Duck> = Box::new(Duck);
    pond.push(duck); // This is valid.

    let mut lake: Vec<Rc<RefCell<Box<Quack>>>> = Vec::new();
    let mallard: Rc<RefCell<Box<Duck>>> = Rc::new(RefCell::new(Box::new(Duck)));
    lake.push(mallard); // This is a type mismatch.
}

上面的代码无法编译,产生以下错误消息:

 expected `alloc::rc::Rc<core::cell::RefCell<Box<Quack>>>`,
    found `alloc::rc::Rc<core::cell::RefCell<Box<Duck>>>`
(expected trait Quack,
    found struct `Duck`) [E0308]
src/main.rs:19     lake.push(mallard);

为什么会这样pond.push(duck)仍然有效lake.push(mallard)不是吗?在这两种情况下,Duck已提供,其中Quack是预料之中的。在前者中,编译器很高兴,但在后者中,则不然。

造成这种差异的原因与CoerceUnsized?


这是正确的行为,尽管有些不幸。

在第一种情况下,我们有这样的:

let mut pond: Vec<Box<Quack>> = Vec::new();
let duck: Box<Duck> = Box::new(Duck);
pond.push(duck);

注意push(), 当被调用时Vec<Box<Quack>>,接受Box<Quack>,而你正在通过Box<Duck>。这是可以的 - rustc 能够理解您想要将装箱值转换为特征对象,如下所示:

let duck: Box<Duck> = Box::new(Duck);
let quack: Box<Quack> = duck;  // automatic coercion to a trait object

在第二种情况下,我们有这样的:

let mut lake: Vec<Rc<RefCell<Box<Quack>>>> = Vec::new();
let mallard: Rc<RefCell<Box<Duck>>> = Rc::new(RefCell::new(Box::new(Duck)));
lake.push(mallard);

Here push()接受Rc<RefCell<Box<Quack>>>当你提供Rc<RefCell<Box<Duck>>>:

let mallard: Rc<RefCell<Box<Duck>>> = Rc::new(RefCell::new(Box::new(Duck)));
let quack: Rc<RefCell<Box<Quack>>> = mallard;

现在有麻烦了。Box<T>是 DST 兼容类型,因此它可以用作特征对象的容器。同样的事情很快也会发生在Rc和其他智能指针时this RFC https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md已实施。然而,在这种情况下,没有从具体类型到特征对象的强制,因为Box<Duck>位于类型的附加层内部(Rc<RefCell<..>>).

请记住,trait 对象是一个胖指针,所以Box<Duck>不同于Box<Quack>在尺寸方面。因此,原则上,它们不直接兼容:你不能只获取字节Box<Duck>并将它们写到哪里Box<Quack>是期待。 Rust执行一个特殊的转换,即它获得一个指向虚表的指针Duck,构造一个胖指针并将其写入Box<Quack>- 类型变量。

当你有Rc<RefCell<Box<Duck>>>然而,rustc 需要知道如何构造和解构两者RefCell and Rc为了对其内部应用相同的胖指针转换。当然,因为这些是库类型,所以它不知道该怎么做。对于任何其他包装器类型也是如此,例如Arc or Mutex甚至Vec。您没想到可以使用Vec<Box<Duck>> as Vec<Box<Quack>>, right?

还有一个事实是,在示例中Rc创建的 RcsBox<Duck> and Box<Quack>不会被连接 - 他们会有不同的参考计数器。

也就是说,只有当您可以直接访问支持 DST 的智能指针时,才会发生从具体类型到特征对象的转换,而不是当它隐藏在其他结构中时。

也就是说,我明白了may be可以允许某些选择类型这样做。例如,我们可以引入某种Construct/Unwrap编译器已知的特征,编译器可以使用这些特征“到达”包装器堆栈内部并在其中执行特征对象转换。然而,还没有人设计这个东西并提供有关它的 RFC - 可能是因为它不是一个广泛需要的功能。

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

代数数据类型的特征 的相关文章

随机推荐

  • 对于 Buffer 等运算符来说,打开和关闭边界的含义是什么?

    我不明白需要打开或关闭边界的 Buffer 运算符的重载 我指的重载是 public static IObservable
  • 如何使用 python 和 Opencv 计算图像中的点数?

    I want to count number of dots in an image The image looks like 我参考了这个 SOF 链接计算图像中的彩色点 https stackoverflow com questions
  • 即使使用stream_set_blocking,PHP SSH2流内容仍为空?

    我正在开发一个工具 它使用 PECL SSH2 扩展通过 SSH2 从远程主机读取 iptables 配置 我能够成功连接到主机 进行身份验证并执行命令 我遇到的问题是有时该流不包含任何数据 Load the current firewal
  • TwoSum 算法:如何改进?

    我想做一个算法并发现这个问题leetcode http www leetcode com 给定一个整数数组 找到两个数字 使它们加起来等于特定的目标数字 函数twoSum 应返回两个数字的索引 以便它们相加达到目标 其中index1 必须小
  • Jython,仅使用 Java 中的 Python 方法?

    阅读和使用时本文 http www rexx com dkuhlman jython course 03 html example the jython classes它假设我们有一个完整的对象定义 包含类和从 python 到 java
  • 查找日期的两个周期之间重叠的天数

    我有两个表 每个表都保存日期期间 从 date1 到 date2 我将在表1和表2中查找两个日期期间之间的重叠天数 Example table1 id FromDate ToDate 1 2000 01 01 2000 02 04 2 20
  • 映射减少计数示例

    我的问题是关于mapreduce programming in java 假设我有 WordCount java 示例 一个标准mapreduce program 我希望map函数收集一些信息 并返回形成如下的reduce函数map
  • 如何从单独的文件下载用于 cmake 中交叉编译的工具链?

    我有一个项目 根目录中有一个 CMakeLists txt 文件 该项目在 Linux 和 OSX 上编译得很好 现在我想为 MIPS OpenWRT 交叉编译它 我想尽可能地自动化它 所以我将使用以下代码来下载工具链并设置编译器变量 Ex
  • 停止并重新启动计时器

    我想停止这个计时器 然后从停止的地方重新启动它 secondsTimer Timer scheduledTimer timeInterval 1 0 target self selector selector addSeconds user
  • 覆盖 FILE_LOG_PATTERN (如果可能的话每个环境)

    我想覆盖 Spring Boot 的默认文件和控制台日志模式以包含一些自定义 MDC 字段 有没有一种简单的方法可以使用application properties yaml 如果没有的话 这将是一个很好的功能 否则我可能不得不复制 Boo
  • 比较当前文件版本和上一个远程存储库

    如何区分我的工作文件版本与远程存储库中的某些先前版本 假设我今天拉取 对本地副本执行 6 8 次提交 然后想要查看我的最新工作版本 给定文件 与远程或任何其他版本上的最新版本之间的差异 要查看 最新工作版本 我将其作为您的工作副本 之间的差
  • 使用 sharekit 在 Facebook 上添加图像和描述

    我正在使用 sharekit 在 Facebook 上分享文本 我想在文本附近添加一张图片 如下图所示 知道如何做到这一点吗 还有其他合适的库 例如 sharekit 吗 谢谢 将 og image 元标记添加到 head html 块中
  • 如何获取使用 AngularDart 的路线?

    这是我的代码 import package angular angular dart class AppModule extends Module AppModule type AppController type LoginControl
  • Biopython无法直接访问异质残基

    我可以使用以下方法直接获取蛋白质 1n31 的残基 residue structure 0 A 100 然而 当我尝试访问异质残基时 例如 residue structure 0 A 2003 我收到错误消息 File
  • 顺序订阅可观察数组

    在这里 我用过forkJoin从 rxjs 并行订阅可观察数组 但我想一一订阅 最好的解决方案是什么 下面是我的代码 var observables Observable forkJoin observables subscribe gt
  • 从 Vaadin 8 Grid 获取列表

    Problem 我有一个 Vaadin 8 Grid 但我找不到提取其中项目的方法 描述 从网格开始 Grid
  • Clojure:避免埃拉托斯特尼筛中的堆栈溢出?

    这是我在 Clojure 中实现的埃拉托斯特尼筛法 基于 SICP 流课程 defn nats from n iterate inc n defn divide p q zero rem q p defn sieve stream lazy
  • 未找到 SDL2_image

    我正在尝试编译以下具有标题的代码 include
  • Vulkan:上传 3 通道图像到设备

    假设主机端有一个3通道图像 float或uint8 需要传输到设备图像 vkCmdCopyBufferToImage用于它 对于设备图像的格式 我看到两个选项 使用 R32G32B32A32 SFLOAT R8G8B8A8 SNORM 并将
  • 代数数据类型的特征

    我无法理解有关代数数据类型特征的规则 这是一个简化的示例 use std rc Rc use std cell RefCell trait Quack fn quack self struct Duck impl Quack for Duc