У меня есть следующий код, который пытается создать составную черту, которая включает все различные комбинации значения / ссылки для метода двух аргументов.
#![recursion_limit = "10"]
// Create a trait with some methods
pub trait Methods2<Other> {
type Output;
fn min(self, other: Other) -> Self::Output;
}
// Create a composite trait that contain multiple traits
trait AllCombos<NonRef>:
Methods2<NonRef, Output = NonRef> + for<'a> Methods2<&'a NonRef, Output = NonRef>
{
}
impl<T, NonRef> AllCombos<NonRef> for T where
T: Methods2<NonRef, Output = NonRef> + for<'a> Methods2<&'a NonRef, Output = NonRef>
{
}
// Implement this trait for f32
impl Methods2<f32> for f32 {
type Output = f32;
fn min(self, other: f32) -> Self::Output {
self.min(other)
}
}
impl Methods2<f32> for &f32 {
type Output = f32;
fn min(self, other: f32) -> Self::Output {
(*self).min(other)
}
}
impl Methods2<&f32> for f32 {
type Output = f32;
fn min(self, other: &f32) -> Self::Output {
self.min(*other)
}
}
impl Methods2<&f32> for &f32 {
type Output = f32;
fn min(self, other: &f32) -> Self::Output {
(*self).min(*other)
}
}
// Create a struct with a generic float inside
#[derive(Debug)]
struct MyStruct<Float> {
x: Float,
}
// Implement to Methods2 trait for MyStruct
impl<Float> Methods2<MyStruct<Float>> for MyStruct<Float>
where
Float: AllCombos<Float>,
for<'a> &'a Float: AllCombos<Float>,
{
type Output = MyStruct<Float>;
fn min(self, other: MyStruct<Float>) -> Self::Output {
MyStruct::<Float> {
x: self.x.min(other.x),
}
}
}
impl<Float> Methods2<MyStruct<Float>> for &MyStruct<Float>
where
Float: AllCombos<Float>,
for<'a> &'a Float: AllCombos<Float>,
{
type Output = MyStruct<Float>;
fn min(self, other: MyStruct<Float>) -> Self::Output {
MyStruct::<Float> {
x: (&self.x).min(other.x),
}
}
}
impl<Float> Methods2<&MyStruct<Float>> for MyStruct<Float>
where
Float: AllCombos<Float>,
for<'a> &'a Float: AllCombos<Float>,
{
type Output = MyStruct<Float>;
fn min(self, other: &MyStruct<Float>) -> Self::Output {
MyStruct::<Float> {
x: self.x.min(&other.x),
}
}
}
impl<Float> Methods2<&MyStruct<Float>> for &MyStruct<Float>
where
Float: AllCombos<Float>,
for<'a> &'a Float: AllCombos<Float>,
{
type Output = MyStruct<Float>;
fn min(self, other: &MyStruct<Float>) -> Self::Output {
MyStruct::<Float> {
x: (&self.x).min(&other.x),
}
}
}
// Lifts a variable into MyStruct
fn lift<Float>(x: Float) -> MyStruct<Float>
where
Float: AllCombos<Float>,
for<'a> &'a Float: AllCombos<Float>,
{
MyStruct { x }
}
// Create an element
fn main() {
let bar = lift(4.0_f32).min(lift(2.0_f32));
//let bar = lift::<f32>(4.0_f32).min(lift::<f32>(2.0_f32));
println!("{:?}", bar.x);
}
Это приводит к ошибке компилятора
error[E0275]: overflow evaluating the requirement `&'a MyStruct<_>: Methods2<MyStruct<_>>`
--> src/main.rs:119:15
|
119 | let bar = lift(4.0_f32).min(lift(2.0_f32));
| ^^^^
|
= help: consider adding a `#![recursion_limit="20"]` attribute to your crate
= note: required because of the requirements on the impl of `for<'a> AllCombos<MyStruct<_>>` for `&'a MyStruct<_>`
= note: required because of the requirements on the impl of `Methods2<MyStruct<MyStruct<_>>>` for `&'a MyStruct<MyStruct<_>>`
= note: required because of the requirements on the impl of `for<'a> AllCombos<MyStruct<MyStruct<_>>>` for `&'a MyStruct<MyStruct<_>>`
= note: required because of the requirements on the impl of `Methods2<MyStruct<MyStruct<MyStruct<_>>>>` for `&'a MyStruct<MyStruct<MyStruct<_>>>`
= note: required because of the requirements on the impl of `for<'a> AllCombos<MyStruct<MyStruct<MyStruct<_>>>>` for `&'a MyStruct<MyStruct<MyStruct<_>>>`
= note: required because of the requirements on the impl of `Methods2<MyStruct<MyStruct<MyStruct<MyStruct<_>>>>>` for `&'a MyStruct<MyStruct<MyStruct<MyStruct<_>>>>`
= note: required because of the requirements on the impl of `for<'a> AllCombos<MyStruct<MyStruct<MyStruct<MyStruct<_>>>>>` for `&'a MyStruct<MyStruct<MyStruct<MyStruct<_>>>>`
= note: required because of the requirements on the impl of `Methods2<MyStruct<MyStruct<MyStruct<MyStruct<MyStruct<_>>>>>>` for `&'a MyStruct<MyStruct<MyStruct<MyStruct<MyStruct<_>>>>>`
= note: required because of the requirements on the impl of `for<'a> AllCombos<MyStruct<MyStruct<MyStruct<MyStruct<MyStruct<_>>>>>>` for `&'a MyStruct<MyStruct<MyStruct<MyStruct<MyStruct<_>>>>>`
note: required by `lift`
--> src/main.rs:109:1
|
109 | / fn lift<Float>(x: Float) -> MyStruct<Float>
110 | | where
111 | | Float: AllCombos<Float>,
112 | | for<'a> &'a Float: AllCombos<Float>,
113 | | {
114 | | MyStruct { x }
115 | | }
| |_^
Теперь это можно решить, заменив вызов на lift
полным синтаксисом, который был закомментирован в вышеприведенном коде
let bar = lift::<f32>(4.0_f32).min(lift::<f32>(2.0_f32));
Хотя это работает, это больший код,это приводит к аннотациям везде, что обременительно. Я бы хотел, чтобы оригинальный вызов
let bar = lift(4.0_f32).min(lift(2.0_f32));
работал. Я могу сделать это, заменив реализацию признака AllCombos
impl<T, NonRef> AllCombos<NonRef> for T where
T: Methods2<NonRef, Output = NonRef>
+ for<'a> Methods2<&'a NonRef, Output = NonRef>
{
}
явными реализациями для каждого типа
impl AllCombos<f32> for f32 {}
impl AllCombos<f32> for &f32 {}
impl AllCombos<MyStruct<f32>> for MyStruct<f32> {}
impl AllCombos<MyStruct<f32>> for &MyStruct<f32> {}
Затем все работает как положено. Однако это несколько неудобно, потому что оно должно быть указано для всех новых типов дважды. Существуют ли другие варианты, которые сохраняют общую реализацию AllCombos
, но впоследствии не требуют полностью определенного синтаксиса для всех вызовов функций для методов в этой черте?