Почему вывод типа не работает во время добавления, когда это происходит во время назначения - PullRequest
4 голосов
/ 09 ноября 2019

Я делаю приложение с помощью ящика rust_decimal. Часть моего приложения включает операции, в которых значение '1' является операндом, поэтому я попытался использовать num_traits :: identifities :: 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 () должен возвращаться в последних двух строках. Почему это?

Ответы [ 2 ]

1 голос
/ 09 ноября 2019

Так Rust выполняет перегрузку операторов. Для выражения типа a+b Rust сначала определит тип a, допустим, что он имеет тип T, а b имеет тип U. Когда T реализует Add<U, Output = V>, сложение может быть скомпилировано, и результирующий тип будет V.

. В некоторых случаях компилятор может вывести тип a по контексту, но это не так. случай в вашем примере.

Поскольку one() имеет несколько типов, которые реализуют черту Add, он не может определить, какой тип one() должен иметь. Возможно, f64 реализует Add<Decimal, Output=Decimal>, что сделает ваше выражение неоднозначным.

В выражении val + one() определен тип первого операнда, но опять-таки имеется несколько реализаций Addкоторый может быть применен: Add<Decimal, Output=Decimal>, Add<f64, Output=Decimal.

Все это может быть решено путем аннотирования one() следующим образом: one::<Decimal>(). Который имеет однозначный тип.

0 голосов
/ 09 ноября 2019

Существует только один тип¹, которому можно присвоить самой Decimal - Decimal, но может быть любое количество типов, которые можно добавить кDecimal.

let add: Decimal = one() + val;

one() должен быть некоторый тип, который реализует Add<Decimal, Output = Decimal>. Но может быть много типов, которые удовлетворяют этому ограничению, и компилятор не выберет один, поэтому вы получите ошибку.

let inc: Decimal = val + one();

В этом случае, если one() имеет тип T, Decimal должен реализовать Add<T, Output = Decimal>. Но опять же, может быть много T s, которые удовлетворяют этому ограничению, и компилятор не выберет одно.

Чтобы исправить любую ошибку, вы можете явно сказать, что вы хотите Decimal версию * 1026. *:

let add = one::<Decimal>() + val;

(аннотация : Decimal в add больше не требуется, поскольку реализация Add однозначно определяет тип Output.)

Десятичное числодопускаются только дополнения с другими десятичными знаками (в противном случае я бы использовал буквальное значение «1»), поэтому я не уверен, что такое неоднозначность в данном конкретном случае.

На самом деле это не такНезависимо от того, сколько типов существует , которые удовлетворяют требованиям. Компилятор не «ищет» типы, удовлетворяющие всем ограничениям;типы должны быть однозначно определены только локальной информацией. Предположим, что работал только один тип, но он был определен в стороннем ящике - должен ли об этом знать компилятор? Или, если есть только один тип, который работает сейчас , но потом вы добавите новый ящик, и теперь есть два таких типа - должен ли ваш код стать безубыточным сейчас? Чтобы избежать такого рода нелокальных поломок, Rust снижается до , выбирая тип для вас. В общем случае, компилятор будет выводить типов;это не спекулирует.

Этот вопрос очень похож на Как можно вычесть 1 из BigInt в Rust?


kХорошо, это не совсемправда. Типы, которые могут быть принудительными до Decimal, также могут быть назначены Decimal переменным. Но принуждение возможно только тогда, когда компилятор уже знает обе стороны назначения, поэтому вы не можете сделать вывод через =, когда происходит принуждение.

«Существуют ограниченные контексты, в которых компилятор Можно выбрать типы. См. этот ответ для одного примера. Стабильная специализация на основе Autoref описывает использование аналогичной техники. Я не смог найти способ применить это к вашей проблеме.

...