Qui*_*ana 6 syntax reference traits rust
到目前为止,在我的项目中,我使用许多特性来允许在注入依赖项的单元测试中进行模拟/存根.然而,到目前为止我所做的一个细节似乎很可疑,我甚至惊讶它甚至编译.我担心会发生一些我看不见或不明白的危险事件.它基于这两种方法签名之间的差异:
fn confirm<T>(subject: &MyTrait<T>) ...
fn confirm<T>(subject: impl MyTrait<T>) ...
Run Code Online (Sandbox Code Playgroud)
我只是impl ...在方法参数中发现了语法,它似乎是唯一记录的方法,但是我的测试已经使用了另一种方式,我根据Go解决了同样的问题(方法的大小)来直觉编译时的参数,当参数可以是接口的任何实现者,并且引用可以来拯救).
这两者有什么区别?为什么他们都被允许?它们都代表合法用例,还是我的参考语法(&MyTrait<T>)严格来说更糟糕?
两者不同,用途不同.两者都很有用,根据情况,一个或另一个可能是最好的选择.
第一种情况,&MyTrait<T>最好是&dyn MyTrait<T>用现代Rust 写的.这是一个所谓的特质对象.该引用指向任何类型的实现MyTrait<T>,并且在运行时动态调度方法调用.为了实现这一点,引用实际上是一个胖指针; 除了指向对象的指针外,它还存储指向对象类型的虚方法表的指针,以允许动态调度.如果对象的实际类型仅在运行时已知,则这是您可以使用的唯一版本,因为在这种情况下您需要使用动态分派.该方法的缺点是存在运行时成本,并且它仅适用于对象安全的特征.
第二种情况,impl MyTrait<T>表示MyTrait<T>再次实现的任何类型,但在这种情况下,需要在编译时知道确切类型.原型
fn confirm<T>(subject: impl MyTrait<T>);
Run Code Online (Sandbox Code Playgroud)
相当于
fn confirm<M, T>(subject: M)
where
M: MyTrait<T>;
Run Code Online (Sandbox Code Playgroud)
对于M代码中使用的每种类型,编译器confim在二进制文件中创建单独的版本,并在编译时静态调度方法调用.如果在编译时已知所有类型,则此版本是首选,因为您不需要支付动态分派到具体类型的运行时成本.
两个原型之间的另一个区别是第一个版本subject通过引用接受,而第二个版本使用传入的参数.但这不是概念上的区别 - 虽然第一个版本无法编写来使用对象,第二个版本可以subject通过引用轻松编写接受:
fn confirm<T>(subject: &impl MyTrait<T>);
Run Code Online (Sandbox Code Playgroud)
鉴于您介绍了促进测试的特性,您可能更喜欢&impl MyTrait<T>.
| 归档时间: |
|
| 查看次数: |
188 次 |
| 最近记录: |