Rust Trait 对象转换

     2023-02-18     52

关键词:

【中文标题】Rust Trait 对象转换【英文标题】:Rust Trait object conversion 【发布时间】:2017-05-27 00:35:54 【问题描述】:

由于此错误的两个实例,以下代码将无法编译:

error[E0277]: trait bound Self: std::marker::Sized 不满足

我不明白为什么在这种情况下需要Sized,因为&self&Any 都是指针,并且该操作不需要知道实现特征的结构的大小,它只需要知道指针本身和它正在转换的类型,因为&self 在 trait 中实现时是通用的。

我认为这可能是编译器强制执行不必要约束的一个实例,我已经考虑向 rust-lang GitHub 存储库提交问题,但我想我应该看看这里是否有人知道我不知道的事情,然后再去提出问题。

use std::any::Any;

trait Component: Any 
    fn as_any(&self) -> &Any 
        self
    

    fn as_any_mut(&mut self) -> &mut Any 
        self
    

对此的替代方法是为实现此特征的结构创建as_any()as_any_mut() 所需的函数,但对于这些结构,实现将始终与此处显示的每个字符完全相同,从而导致多个实例相同的样板代码。

【问题讨论】:

我删除了我的答案,因为我找不到足够快的文档链接。不过,我的理解是,traits 中的Self 是未调整大小的,并且如果没有将您的特征明确标记为Sized,编译器会将其视为未调整大小和错误。 我认为制作所需的方法是要走的路。至少我以前见过这种模式。为避免重复代码,您可以编写一个简单的宏 impl_conversion_functions!() 或类似的东西。 【参考方案1】:

动态大小的类型也可以实现特征。特别是,当你定义一个对象安全的 trait 时,编译器还会定义一个与 trait 同名的动态大小的类型,这样你就可以使用 &Component 这样的对象类型。

&Component&Any 等对象类型不仅仅是普通的指针;它们是胖指针。胖指针结合了指向数据的指针和另一段数据:对于对象类型,它是指向 vtable 的指针;对于切片,它是切片的长度。

当从常规指针(例如 &Button)转换为对象类型时,编译器静态地知道将哪个 vtable 放入胖指针(例如 Button 的 vtable 对应于 Any)。另一方面,Rust 不支持从一个对象类型转换为另一个对象类型(例如,从 &Component&Any),因为对象中没有足够的数据来初始化新的胖指针。这就是编译器在错误消息中添加此注释的原因:

= note: required for the cast to the object type `std::any::Any + 'static`

有两种方法可以解决这个问题:

    要求所有实现Component 的类型都是Sized

    trait Component: Any + Sized 
        fn as_any(&self) -> &Any 
            self
        
    
        fn as_any_mut(&mut self) -> &mut Any 
            self
        
    
    

    这会导致您根本无法使用 &ComponentBox<Component> 等对象类型。

    使as_anyas_any_mut 方法仅在SelfSized 时可用:

    trait Component: Any 
        fn as_any(&self) -> &Any
            where Self: Sized
        
            self
        
    
        fn as_any_mut(&mut self) -> &mut Any
            where Self: Sized
        
            self
        
    
    

    这样,您仍然可以为 trait 使用对象类型,但您将无法对它们调用 as_anyas_any_mut

【讨论】:

这是有道理的。不幸的是,对于我的特殊情况,我确实需要能够在特征对象上调用这些函数。我看看能不能找到别的方法【参考方案2】:

我发现我认为不需要新编译器功能的出色解决方案。

pub trait Component 
    // ...


pub trait ComponentAny: Component + Any 
    fn as_any(&self) -> &Any;
    fn as_any_mut(&mut self) -> &mut Any;


impl<T> ComponentAny for T
    where T: Component + Any

    fn as_any(&self) -> &Any 
        self
    

    fn as_any_mut(&mut self) -> &mut Any 
        self
    

从这里开始,我只是将我的所有 API 更改为接受 ComponentAny 而不是 Component。因为Any 会自动为任何'static 类型实现,所以ComponentAny 现在会为任何实现Component'static 类型自动实现。感谢Is there a way to combine multiple traits in order to define a new trait? 的想法。

【讨论】:

Rust 中 trait 的冲突实现

】Rust中trait的冲突实现【英文标题】:ConflictingimplementationsoftraitinRust【发布时间】:2016-08-2605:57:47【问题描述】:我想为&amp;\'astr和最大为i32的整数实现一个自定义特征,但Rust不允许我这样做:usestd::convert::Into;pubtraitUiIdfnpush(... 查看详情

如何使 Rust Generic Struct/Trait 需要 Box<other trait>?

】如何使RustGenericStruct/Trait需要Box<othertrait>?【英文标题】:HowtomakeaRustGenericStruct/TraitrequireaBox<othertrait>?【发布时间】:2021-10-0116:40:17【问题描述】:我有一个特征Agent代表模拟中的代理,还有一个结构SimpleAgent实现了这... 查看详情

rust学习教程25-特征trait(代码片段)

...入Rust编程学院,一起学习交流:QQ群:1009730433特征Trait如果我们想定义一个文件系统,那么把该系统跟底层存储解耦是很重要的。文件操作主要包含三个:open、write、read,这些操作可以发生在硬盘,也可以发生... 查看详情

rust学习教程25-特征trait(代码片段)

...入Rust编程学院,一起学习交流:QQ群:1009730433特征Trait如果我们想定义一个文件系统,那么把该系统跟底层存储解耦是很重要的。文件操作主要包含三个:open、write、read,这些操作可以发生在硬盘,也可以发生... 查看详情

rust tokio trait bounds 不满足 forward 方法

】rusttokiotraitbounds不满足forward方法【英文标题】:rusttokiotraitboundswerenotsatisfiedonforwardmethod【发布时间】:2021-08-0815:20:26【问题描述】:我在我的rust项目中升级了wrap和tokio,升级后转发方法出错。我翻遍了文档,但是新版tokio框架... 查看详情

「rust进阶笔记」rust之derive特性总结(代码片段)

...artialOrdClone:从&T的一个拷贝创建TCopy:把一个类型的move转换为copyHash:从&T计算它的哈希Default:创建一个数据类型的空实例Debug:用:?格式化一个值Debug用于程序员输出Debug trait用于开启格式化字符串中的调试格式,其通... 查看详情

rust语言圣经25-特征trait(代码片段)

原文链接:https://course.rs/basic/trait/trait.html 欢迎大家加入Rust编程学院,中国最好的Rust学习社区官网:https://college.rsQQ群:1009730433特征Trait如果我们想定义一个文件系统,那么把该系统跟底层存储解耦是很重要... 查看详情

Rust struct 可以借用 "&'a mut self" 两次,那为啥 trait 不能呢?

】Ruststruct可以借用"&\\\'amutself"两次,那为啥trait不能呢?【英文标题】:Ruststructcanborrow"&\'amutself"twice,sowhycan\'tatrait?Ruststruct可以借用"&\'amutself"两次,那为什么trait不能呢?【发布时间】:2014-11-2907... 查看详情

使用 Rust DBUS 库时,不满足 trait bound `dbus::arg::Get`

】使用RustDBUS库时,不满足traitbound`dbus::arg::Get`【英文标题】:Thetraitbound`dbus::arg::Get`isnotsatisfiedwhenusingtheRustDBUSlibrary【发布时间】:2017-05-1712:00:07【问题描述】:我正在尝试使用thedbus-rs库通过GetSettings方法从NetworkManager获取连接... 查看详情

rust语言圣经26-特征对象(代码片段)

...st学习社区官网:https://college.rsQQ群:1009730433特征对象在上一节中有一段代码无法通过编译:fnreturns_summarizable(switch:bool)->implSummaryifswitchPost//...elseWeibo//...其中Post和Weibo都实现了Summary特征,因此上面的函数试图通过返... 查看详情

rust编程语言入门之泛型trait生命周期(代码片段)

泛型、Trait、生命周期一、提取函数消除重复fnmain()letnumber_list=vec![34,50,25,100,65];letmutlargest=number_list[0];fornumberinnumber_listifnumber>largestlargest=number;println!("Thelargestnumberis",largest);重复代码重复代码的危害:容易出错需求变更时需要在... 查看详情

是啥使某物成为“特征对象”?

】是啥使某物成为“特征对象”?【英文标题】:Whatmakessomethinga"traitobject"?是什么使某物成为“特征对象”?【发布时间】:2015-02-1811:53:58【问题描述】:最近的Rust更改使“特征对象”对我来说更加突出,但我对究竟是... 查看详情

为啥 trait 中的泛型方法需要调整 trait 对象的大小?

】为啥trait中的泛型方法需要调整trait对象的大小?【英文标题】:Whydoesagenericmethodinsideatraitrequiretraitobjecttobesized?为什么trait中的泛型方法需要调整trait对象的大小?【发布时间】:2017-03-0607:38:54【问题描述】:我有这个代码(playg... 查看详情

为啥在某些 trait 方法调用中会出现来自 &mut 的引用减弱?

...】:2018-09-0209:18:45【问题描述】:Rust中可用的少数隐式转换之一是pointerweakening,它可以将&amp 查看详情

rust特征对象(代码片段)

...真丑啊....看完trait之后,我整个人都不好了,然后看特征对象的时候,我人是比较懵逼的。0概述特征对象:指向实现了某个特征的一系列实例。这种映射关系存在一张表内(vtable),可以在运行时通过特征对象找到具体调用的类型... 查看详情

scala入门系列:面向对象之trait

基础知识1将trait作为接口使用此时Trait就与Java中的接口非常类似,不过注意,在Scala中无论继承还是trait,统一都是extends关键字。Scala跟Java8前一样不支持对类进行多继承,但是支持多重继承trait,使用with关键字即可traitHelloTrait{de... 查看详情

scala编程入门---面向对象编程之trait高级知识

trait调用链Scala中支持让类继承多个Trait后,依次调用多个Trait中的同一个方法,只要让多个trait的同一个方法中,在最后都执行super.方法即可类中调用多个trait中都有这个方法时,首先会从最右边的trait的方法开始执行,然后依次... 查看详情

rust入坑指南:海纳百川(代码片段)

今天来聊Rust中两个重要的概念:泛型和trait。很多编程语言都支持泛型,Rust也不例外,相信大家对泛型也都比较熟悉,它可以表示任意一种数据类型。trait同样不是Rust所特有的特性,它借鉴于Haskell中的Typeclass。简单来讲,Rust中... 查看详情