rust - 核心中的运算符真的是循环定义的吗?

标签 rust operators

我们可以在 core::ops 中实现特征来为我们的类型定义运算符的行为。特征本身用 #[lang =...] 属性进行注释,因此编译器知道哪些特征和运算符属于一起。

例如,原始类型的 Add 实现如下所示(从 here 手动扩展和简化的宏):

impl Add for i32 {
    type Output = i32;

    fn add(self, other: i32) -> i32 {
        self + other
    }
}

令我惊讶的是,该实现在内部使用了 + 运算符,这可能会调用 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;
}

编译器警告函数不能不重复返回,并且在 Debug 模式下运行该程序会因致命运行时错误:堆栈溢出而正确停止。

编译器如何知道如何将两个数字相加而不落入递归漏洞?

最佳答案

How does the compiler know to add two numbers without falling into a recursive loophole?

因为编译器就是编译器,而且编译器知道它不需要Add 实现来添加两个数字。如果它不断折叠,它只是添加它们。如果它正在生成代码,它会告诉 LLVM 在运行时添加它们。

那些 Add 实现并不是告诉编译器如何添加数字,它们是为数字实现 Add 以便用户代码可以通过Add trait 就像任何用户定义的类型一样。如果这些实现不存在,那么您将无法在通用方法中添加数字,因为它们不会实现 Add

换句话说:Add 是编译器在不知道如何添加内容时使用的。但它已经知道如何添加数字,所以它不需要它们。提供它们是为了与其他类型保持一致。

关于rust - 核心中的运算符真的是循环定义的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50254315/

相关文章:

algorithm - Rust:从二进制字符串表示形式转换为 ASCII 字符串

rust - 如何将 Peekable 迭代器转换回原始迭代器?

c - 在 C 的条件之外的语句中使用 '&&' 和 '||'

c++ - 为什么 implicit == on map<<int,MyClass> 不编译?

c++ - 在 C++ 中用类型为 'double' 的乘数将复数对象与实部和虚部相乘

casting - 无法将字符串从标准输入解析为 float - Rust

arrays - 结构中的枚举数组打印变体名称和值

javascript - 尝试从函数返回有效的电子邮件

Python 等效于 Perl 文件测试可读 (-r)、可写 (-w) 和可执行 (-x) 运算符

file - 无法使用 std::fs 方法读取 Docker 镜像中的文件