我没能投出dyn SomeTrait + Send + Syncdyn SomeTrait + Sync.

更具体地说,我正在try 投掷&Vec<Box<dyn SomeTrait + Send + Sync>>&Vec<Box<dyn SomeTrait + Sync>>.

我试着简单地安抚as suggested here,也试着用as,但两种方法都不管用.

我怎样才能实现我想要的?

错误消息为

expected trait `ToSql + Sync`, found trait `ToSql + Send + Sync`

编辑:另外,我很想知道为什么这不能正常工作,因为转换应该是可能的,因为我们知道每个dyn SomeTrait + Send + Sync>都满足SomeTrait + Sync

推荐答案

让我们从困难的事情开始吧.如果你想要一个简单的解决方案,跳到答案的末尾(最后一节).


因此:事实是,它确实可以奏效.为什么不是呢?好吧,显然有一些问题,但主要问题可能是没有人致力于这一点.There is a thread in internals.rust-lang.org discussing that.

首先,我们需要了解coercionsubtyping之间的区别.

Coercing类型TU意味着当你有一个类型为T的东西,并且你想把它转换成类型U,编译器可以自动为你完成这项工作.您只需要声明您想要类型U,编译器就会施展它的魔力,为您提供它.例如,对数组(&[T; N])的引用可以被强制为对片(&[T])的引用.当您拥有对数组的引用并将其传递给需要对片的引用的对象(例如函数)时,编译器会自动插入代码以将指向数组的指针(在汇编代码中引用数组)转换为指针+大小(在汇编代码中对片的引用).

一般来说,每一次转变都可能是一种胁迫.它只需要内置到语言中,编译器必须知道如何插入代码才能做到这一点.然而,Rust的原则是expensive things should be explicit,因此,胁迫(隐含的)需要便宜.

对我们来说,理解胁迫的重要一点是they're not transitive.也就是说,如果类型T可以被强制为U,这并不意味着G<T>可以被强制为G<U>.或者,简单地说,&[T; N]可以被强迫到&[T]的事实并不意味着我们也可以强迫Vec<&[T; N]>Vec<&[T]>.原因很简单:因为强制需要实际插入代码来执行转换,所以我们不知道如何为包装器类型生成代码.我们知道将&[T; N]转换为&[T](通过简单地附加大小)并不意味着我们知道将&[T; N]s的矢量转换为&[T]s的矢量,这需要分配和复制(因为&[T]的大小是&[T; N]的两倍).

subtyping relationship是完全不同的一件事.如果类型TU的子类型,那就意味着any 100 is also 101.OOP语言中的基类就是一个典型的例子.Derived的实例也是Base的实例.这确实意味着,与强制一样,指向Derived的指针可以转换为指向Base的指针,但与强制不同的是,指向this doesn't require inserting any conversion code的指针可以转换为指向Base的指针.

在 compose 本文时,Rust中唯一的子类型是终身关系.例如,'static是任意生存期的子类型,这意味着&'static T是任意&'a T的子类型.这就是为什么你可以给&'static T分,而你应该给&'a T分.

因为不需要转换代码,所以子类型is是可传递的.您可以将Vec<&'static T>转换为Vec<&'a T>.但有一个例外,那就是差异,我现在就不谈了.


现在来看重要的一点:从dyn Trait + Send + Syncdyn Trait + Sync的转换(换句话说,从dyn Trait删除了额外的自动特征界限)是强制的,而不是子类型.这就是您无法将&Vec<Box<dyn Trait + Send + Sync>>转换为&Vec<Box<dyn Trait + Sync>>的原因--转换是不可传递的.

它没有理由不是子类型-转换不需要代码,除此之外,正如我已经说过的,没有人做过这方面的工作.


但我们还能这样做吗?

使用不安全的代码是的;但也不是.

句号,不允许从&Vec<Box<dyn Trait + Send + Sync>>转换到&Vec<Box<dyn Trait + Sync>>.即使假设Box<dyn Trait + Send + Sync>Box<dyn Trait + Sync>具有相同的布局,也不能保证包含它们的两个Vec也具有相同的布局.所以你所要求的是不可能实现的.

但是类似的东西怎么样:从Vec<Box<dyn Trait + Send + Sync>>转换到Vec<Box<dyn Trait + Sync>>(没有参考).或者类似地,&[Box<dyn Trait + Send + Sync>]&[Box<dyn Trait + Sync>].或者甚至是&Vec<Box<dyn Trait + Send + Sync>>&[&(dyn Trait + Send + Sync)]

我们可以使用Vec::from_raw_parts()(或std::slice::from_raw_parts())来构建Vec(或片),而不依赖于其布局细节.但我们仍然需要指向dyn Trait + AutoTrait的指针与指向dyn Trait的指针具有相同的布局.这能行得通吗?

嗯,目前是这样的,我相信将来也会这样.但任何地方都没有记录,所以我不会依赖于这一点.


然而,从你的 comments 中,看起来你想要的只是一片&[&(dyn SomeTrait + Sync)],而你甚至不在乎你是否分配.嗯,这可以很容易地做到:

let v2: Vec<&(dyn SomeTrait + Sync)> = v.iter().map(|item| &**item as _).collect();
let v2: &[&(dyn SomeTrait + Sync)] = v2.as_slice();

Rust相关问答推荐

空字符串转换为Box字符串时是否分配?<>

有没有办法避免在While循环中多次borrow `*分支`

使用铁 rust S还原对多个数组执行顺序kronecker积

如何计算迭代器适配器链中过滤的元素的数量

取得本地对象字段的所有权

无符号整数的Rust带符号差

变量需要parse()中的显式类型

循环访问枚举中的不同集合

如何迭代属性以判断相等性?

为什么RefCell没有与常规引用相同的作用域?

为什么我必须使用 PhantomData?在这种情况下它在做什么?

我可以解构self 参数吗?

如何使用 Bincode 在 Rust 中序列化 Enum,同时保留 Enum 判别式而不是索引?

部署Rust发布二进制文件的先决条件

有什么办法可以追踪泛型的单态化过程吗?

push 方法是否取得所有权?

为什么我不能克隆可克隆构造函数的Vec?

在 Rust 中,将可变引用传递给函数的机制是什么?

为什么可以从闭包中返回私有 struct

基于名称是否存在的条件编译