Скажем, я хочу написать обобщенную функцию, которая принимает некоторое значение типа 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>
или подобное для любого встроенного типа.