gpt4 book ai didi

syntax - &Trait 和 impl Trait 用作方法参数时有什么区别?

转载 作者:行者123 更新时间:2023-11-29 07:47:36 26 4
gpt4 key购买 nike

到目前为止,在我的项目中,我使用了许多特征来允许在单元测试中模拟/ stub 以注入(inject)依赖项。然而,到目前为止我正在做的事情的一个细节似乎非常可疑,以至于我很惊讶它甚至可以编译。我担心正在发生一些我看不到或不理解的危险事情。它基于这两个方法签名之间的差异:

fn confirm<T>(subject: &MyTrait<T>) ...
fn confirm<T>(subject: impl MyTrait<T>) ...

我刚刚发现 impl ...方法参数中的语法,这似乎是执行此操作的唯一记录方式,但我的测试已经使用另一种方式通过了,这是我根据 Go 解决相同问题的方式(编译时方法参数的大小,当参数可以是接口(interface)的任何实现者时,引用可以来拯救)。

这两者有什么区别?为什么他们都被允许?它们是否都代表合法的用例,或者我的引用语法 ( &MyTrait<T>) 严格来说是一个更糟糕的主意?

最佳答案

两者不同,用途不同。两者都有用,根据具体情况,其中一个可能是最佳选择。

第一种情况,&MyTrait<T> , 最好写成 &dyn MyTrait<T>在现代 Rust 中。它是一个所谓的特质对象。引用指向任何实现 MyTrait<T> 的类型,并且方法调用在运行时动态调度。为了使这成为可能,引用实际上是一个胖指针;除了指向对象的指针外,它还存储指向对象类型的虚方法表的指针,以允许动态调度。如果你的对象的实际类型只在运行时才知道,这是你唯一可以使用的版本,因为在这种情况下你需要使用动态调度。该方法的缺点是存在运行时成本,并且它仅适用于 object-safe 的特征。 .

第二种情况,impl MyTrait<T> , 表示实现 MyTrait<T> 的任何类型再次,但在这种情况下,需要在编译时知道确切的类型。原型(prototype)

fn confirm<T>(subject: impl MyTrait<T>);

相当于

fn confirm<M, T>(subject: M)
where
M: MyTrait<T>;

对于每种类型 M在您的代码中使用,编译器会创建一个单独的版本 confim在二进制文件中,方法调用在编译时静态分派(dispatch)。如果在编译时已知所有类型,则此版本更可取,因为您无需支付动态分派(dispatch)到具体类型的运行时成本。

两个原型(prototype)之间的另一个区别是第一个版本接受 subject通过引用,而第二个版本使用传入的参数。这不是概念上的区别,虽然 - 虽然第一个版本不能编写为使用对象,但第二个版本可以很容易地编写为接受 subject通过引用:

fn confirm<T>(subject: &impl MyTrait<T>);

鉴于您引入了便于测试的特征,您可能更喜欢 &impl MyTrait<T> .

关于syntax - &Trait 和 impl Trait 用作方法参数时有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53769176/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com