Обобщенно умножьте значения разного типа в Rust - PullRequest
3 голосов
/ 01 ноября 2019

Скажем, я хочу написать обобщенную функцию, которая принимает некоторое значение типа K и умножает его на f64. Следующие работы:

fn generic1<K>(a: K, b: f64) -> K
where
    K: Mul<f64, Output = K> + Add<K, Output = K> + Copy,
    f64: Mul<K, Output = K>,
{
     a * b + b * a
}

Однако я больше не могу, например, умножить два числа с плавающей запятой в пределах одной и той же функции. По сути, кажется, что граница f64: Mul<K, Output = K> переопределяет / скрывает (?) Значение impl Mul<f64> for f64. Вот пример:

fn generic2<K>(a: K, b: f64) -> K
where
    K: Mul<f64, Output = K> + Add<K, Output = K> + Add<f64, Output = K> + Copy,
    f64: Mul<K, Output = K>,
{
     a * b + b * a + b * b
}

, который выдает следующую ошибку компилятора:

   |
16 |      a * b + b * a + b * b
   |                          ^ expected type parameter, found f64
   |
   = note: expected type `K`
              found type `f64`

( детская площадка ), т.е. f64 * <whatever> теперь работает только для <whatever> типа K.

В качестве обходного пути я могу использовать полный синтаксис <f64 as Mul<f64>>::mul(b, b), но это крайне уродливо. Такое ощущение, что компилятор должен видеть, что он может использовать вывод типа f64 и, следовательно, использовать реализацию f64 * f64 вместо f64 * K.

Менее абстрактный пример того, что я хочучтобы сделать: K может быть векторным типом или скалярным типом, и я хочу иметь возможность выполнять коммутативное скалярное умножение с ним общим способом.

Что здесь происходит? Почему я больше не могу умножать b * b?

Обновление : @ Ömer-erden заметил, что это работает, если явно указать f64: Mul<f64, Output = f64>. К сожалению, этот обходной путь не работает при импорте alga ящика - см. Обновленную ссылку на игровую площадку .

Я не совсем уверен, что делает водоросль, чтобы сломать и без того странныйповедение. Как уже отмечал Омер, похоже, что это скорее ошибка или ограничение средства проверки типов, чем ошибка в alga / что угодно, поскольку в идеале ни один код не должен иметь возможность нарушать разрешение impl Mul<f64, Output = f64> или подобное для любого встроенного типа.

1 Ответ

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

Это ограничение, которое говорит, что когда K является правильным операндом, вы можете умножить f64 на K, и результат будет K. Также говорит, что f64 должен реализовать Mul<K, Output = K>

f64: Mul<K, Output = K>,

Я пока не знаю, это может произойти из-за ограниченной мощности средства проверки типов или ошибки, но каким-то образом реализация Mul<f64, Output = f64> на f64становится неоднозначным из-за ограничения Mul<K, Output = K>.

, если вы явно укажете ожидаемое поведение, которое в вашем случае составляет Mul<f64, Output = f64>:

fn generic2<K>(a: K, b: f64) -> K
where
    K: Mul<f64, Output = K> + Add<K, Output = K> + Add<f64, Output = K> + Copy,
    f64: Mul<K, Output = K> + Mul<f64, Output = f64>,
{
    a * b + b * a + b * b
}

, оно будет работать как ожидалось.

Детская площадка

...