Rust 为什么类型推断在加法期间不起作用,而在赋值期间起作用

Rust 为什么类型推断在加法期间不起作用,而在赋值期间起作用,rust,type-inference,Rust,Type Inference,我正在用rust_decimal板条箱制作一个应用程序。我的应用程序的一部分涉及值“1”是操作数的操作,因此我尝试使用num_traits::identies::one()并遇到一些意外错误: use rust_decimal::Decimal; use num_traits::identities::*; fn foo(val : Decimal) { let _1 = one(); // E0282, expected let _one : Decimal = one();

我正在用rust_decimal板条箱制作一个应用程序。我的应用程序的一部分涉及值“1”是操作数的操作,因此我尝试使用num_traits::identies::one()并遇到一些意外错误:

use rust_decimal::Decimal;
use num_traits::identities::*;

fn foo(val : Decimal) {
    let _1 = one(); // E0282, expected
    let _one : Decimal = one(); // Ok, expected
    let add : Decimal = one() + val; // E0283, unexpected
    let inc : Decimal = val + one(); // E0284, unexpected
}

令我惊讶的是,编译器无法确定在最后两行中要返回什么类型的one()。这是为什么?

只有一种类型可以分配给
十进制
-
十进制
本身-但是可以添加到
十进制
中的类型可能有很多

let add: Decimal = one() + val;
one()
必须是实现
Add
的某种类型。但是可能有许多类型满足该约束,并且编译器不会选择其中一种,因此会出现错误

let inc: Decimal = val + one();
在这种情况下,如果
one()
的类型为
T
Decimal
必须实现
Add
。但同样,可能有许多
T
s满足此约束,编译器不会选择一个

要修复这两个错误,您可以明确表示希望使用
one
Decimal
版本:

let add = one::<Decimal>() + val;
let add=one::()+val;
(不再需要
添加
上的
:十进制
注释,因为
添加
实现明确地确定了
输出
类型。)

Decimal只允许与其他小数相加(否则我将使用文字“1”),因此我不确定在这种特殊情况下的歧义是什么

实际上,满足需求的类型有多少并不重要。编译器不会“寻找”满足所有约束的类型;必须仅通过本地信息明确地确定类型。假设只有一种类型有效,但它是在第三方板条箱中定义的;编译器应该知道吗?或者,如果今天只有一种类型可以工作,但是明天您将包含一个新的板条箱,并且有两种这样的类型,那么您的代码是否应该中断?为了避免这种非局部断裂,Rust拒绝为您选择一种类型。一般来说,编译器只会推断类型;这不是推测

这个问题很像


好吧,这绝对不是真的。可以强制为
Decimal
的类型也可以指定给
Decimal
变量。但是强制只有在编译器已经知道赋值的两边时才可能,因此无法通过
=
推断强制何时发生


²编译器可以在有限的上下文中选择类型。参见示例。描述如何使用类似的技术。我找不到一种方法将此应用于您的问题。

这就是Rust如何解决运算符重载的问题。 对于像
a+b
这样的表达式,Rust将首先确定
a
的类型,假设它具有类型
T
b
具有类型
U
。 当
T
实现
Add
时,可以编译加法,得到的类型将是
V

在某些情况下,编译器可以根据上下文推断
a
的类型,但在您的示例中并非如此

因为
one()
有多个实现
Add
特性的类型,所以它无法确定
one()
应该具有哪种类型。可能是
f64
实现了
Add
,这会使表达式变得模棱两可


在表达式
val+one()
中,确定了第一个操作数的类型,但仍然可以应用
Add
的多个实现:
Add
Add这是否回答了您的问题?摘要:可能有许多类型实现了
Add
,编译器不会选择一种。要修复它,最简单的方法可能是使用turbofish:
let add=one::()+val
(不需要
add
上的
:Decimal
注释,因为
add
实现明确地确定了
输出类型。)有没有办法让编译器显示它无法选择的内容?Decimal只允许与其他小数相加(否则我将使用文字“1”),因此我不确定在这种特殊情况下的歧义是什么。