核心运营商是否真的以循环方式定义? [英] Are operators in core really defined circularly?
问题描述
我们可以实现core::ops
中的特征来为我们的类型定义运算符的行为.这些特征本身使用#[lang =...]
属性进行注释,因此编译器知道哪些特征和运算符属于同一特征.
We can implement the traits in core::ops
to define the behavior of operators for our types. The traits themselves are annotated with #[lang =...]
attributes so the compiler knows which traits and operators belong together.
For example, the Add
implementation for primitive types looks like this (macro manually expanded and simplified from here):
impl Add for i32 {
type Output = i32;
fn add(self, other: i32) -> i32 {
self + other
}
}
令我惊讶的是,该实现在内部使用了+
运算符,该运算符可能调用了self.add(other)
,从而导致了无限递归.显然,事情不会像这样发生,因为3 + 4
这样的表达式(假设没有固定的折叠)可以很好地工作.
To my surprise, the implementation uses the +
operator internally, which presumably calls self.add(other)
, resulting in an infinite recursion. Obviously, things do not happen like this because expressions like 3 + 4
(assuming no constant folding) work perfectly fine.
现在考虑对Add
特征的这种天真的实现:
Now consider this naive implementation of the Add
trait:
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;
}
编译器警告function cannot return without recurring
并以fatal runtime error: stack overflow
正确停止在Debug模式下运行该程序.
The compiler warns that function cannot return without recurring
and running this program in Debug mode properly stops with fatal runtime error: stack overflow
.
编译器如何知道如何将两个数字相加而不会陷入递归漏洞?
How does the compiler know how to add two numbers without falling into a recursive loophole?
推荐答案
编译器如何知道将两个数字相加而不导致递归漏洞?
How does the compiler know to add two numbers without falling into a recursive loophole?
因为编译器是编译器,并且编译器知道不需要Add
实现即可将两个数字相加.如果正在不断折叠,则只需添加它们即可.如果生成代码,它会告诉LLVM在运行时添加它们.
Because the compiler is the compiler, and the compiler knows it doesn't need an Add
implementation to add two numbers. If it's doing constant folding, it just adds them. If it's generating code, it tells LLVM to add them at runtime.
那些Add
实现无法告诉编译器如何添加数字,它们是为数字实现Add
,以便用户代码可以像任何用户定义的一样通过Add
特性添加数字.类型.如果这些实现不存在,那么您将无法在通用方法中添加数字,因为它们无法实现Add
.
Those Add
implementations aren't there to tell the compiler how to add numbers, they're to implement Add
for numbers so that user code can add numbers via the Add
trait just like any user-defined type. If those implementations didn't exist, then you wouldn't be able to add numbers in generic methods, because they wouldn't implement Add
.
换句话说:Add
是编译器在不知道如何添加内容的情况下使用的内容.但是它已经知道如何添加数字,因此不需要它们.提供它们是为了与其他类型保持一致.
To put it another way: Add
is what the compiler uses when it doesn't otherwise know how to add things. But it already knows how to add numbers, so it doesn't need them. They're provided for consistency with other types.
这篇关于核心运营商是否真的以循环方式定义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!