核心运营商是否真的以循环方式定义? [英] Are operators in core really defined circularly?

查看:97
本文介绍了核心运营商是否真的以循环方式定义?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们可以实现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.

例如,原始类型的Add实现看起来像这样(宏从

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆