我们可以实现traits core::ops来定义我们类型的运算符的行为.特征本身用#[lang =...]属性注释,因此编译器知道哪些特征和操作符属于一起.
例如,Add基本类型的实现看起来像这样(宏从这里手动扩展和简化):
impl Add for i32 {
type Output = i32;
fn add(self, other: i32) -> i32 {
self + other
}
}
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是,该实现在+内部使用运算符,可能会调用self.add(other),从而导致无限递归.显然,事情不会发生这种情况,因为像3 + 4(假设没有不断的折叠)这样的表达式可以完美地运行.
现在考虑这个特性的天真实现Add:
use std::ops::Add;
struct Foo;
impl Add for Foo {
type Output = Foo;
fn add(self, other: Foo) -> Foo {
self + other
}
}
fn main() {
let two_foo = Foo + Foo;
}
Run Code Online (Sandbox Code Playgroud)
编译器警告function cannot return without recurring并在调试模式下运行此程序正确停止fatal runtime error: stack overflow.
编译器如何知道如何添加两个数字而不会陷入递归漏洞?
编译器如何知道添加两个数字而不会陷入递归漏洞?
因为编译器是编译器,并且编译器知道它不需要Add实现来添加两个数字.如果它正在进行恒定折叠,它只是添加它们.如果它生成代码,它会告诉LLVM在运行时添加它们.
那些Add实现不是告诉编译器如何添加数字,它们是Add为数字实现的,这样用户代码就可以Add像任何用户定义的类型一样通过特征添加数字.如果这些实现不存在,那么您将无法在泛型方法中添加数字,因为它们不会实现Add.
换句话说:Add当编译器不知道如何添加内容时,编译器会使用它.但它已经知道如何添加数字,所以它不需要它们.提供它们与其他类型的一致性.
| 归档时间: |
|
| 查看次数: |
306 次 |
| 最近记录: |