Возможно ли реализовать перегрузку оператора для apply::Apply?

#rust #functional-programming #operator-overloading

#Ржавчина #функциональное программирование #перегрузка оператора

Вопрос:

Есть ли какой-либо способ реализовать перегрузку оператора для apply::Apply ?

В Rust многие операторы могут быть перегружены через черты. То есть некоторые операторы могут использоваться для выполнения различных задач на основе их входных аргументов. Это возможно, потому что операторы являются синтаксическим сахаром для вызовов методов. Например, оператор в a b вызывает метод add (как в a.add(b) ). Этот метод add является частью функции Add. Следовательно, оператор может использоваться любым разработчиком функции добавления.

 /// Represents a type which can have functions applied to it (implemented
/// by default for all types).
pub trait Apply<Res> {
    /// Apply a function which takes the parameter by value.
    fn apply<F: FnOnce(Self) -> Res>(self, f: F) -> Res
    where Self: Sized {
        f(self)
    }
}

impl<T: ?Sized, Res> Apply<Res> for T {
    // use default definitions...
}
 

Перегрузка ящика

Например,

 let string = 1 >> (|x| x * 2) >> (|x: i32| x.to_string());
 

для

 let string = 1.apply(|x| x * 2).apply(|x: i32| x.to_string());
 

Комментарии:

1. Что вы подразумеваете под «перегрузкой оператора»? Вы всегда можете реализовать черты в std::ops .

2. Я думаю, что я прояснил свой вопрос, и термин взят из официального документа.

Ответ №1:

Не совсем. Операторы не переходят к признакам, они переходят к типам. Не имеет смысла спрашивать «какова реализация >> for Apply «, но имеет смысл спросить «какова реализация >> for u8 » . Итак, что вы могли бы попытаться сделать, это определить Apply , как вы его определили, и теперь:

 impl<T, Res, F> std::ops::Shr<F> for T
where
    T: Apply<Res>,
    F: FnOnce(T) -> Res
{
    type Output = Res;
    fn shr(self, rhs: F) -> Res {
        rhs(self)
    }
}
 

Это почти работает, за исключением того, что компилятор сообщает об ошибке, ссылаясь

для параметра типа могут быть реализованы только признаки, определенные в текущем ящике

Причина этой ошибки в том, что у вас нет гарантии, что другой ящик не реализовал ту же особенность для того же типа. Если другой ящик определил

 impl<F: FnOnce(MyType) -> String> std::ops::Shr<F> for MyType { ... }
 

неясно, что должно произойти, поскольку теперь >> оператор был определен дважды для одного и того же типа. Вы могли бы написать такое impl , если MyType бы вы заменили какой-то определенный тип, локальный для вашего ящика, но, конечно, теперь >> это не будет работать для всех других типов.

Комментарии:

1. Что ж, спасибо, и я знаю, что операторы относятся к типам, однако в официальном документе говорится: «В Rust многие операторы могут быть перегружены через черты». это я должен процитировать сейчас в своем вопросе, и если вас не устраивает выражение там, пожалуйста, предъявите им претензии.

2. @KenSmooth в нем написано «может быть перегружен с помощью черт», что означает, что они могут быть перегружены с помощью черт, а не то, что они могут быть перегружены с помощью черт

3. Я думаю, что такой контекст довольно ясен в моем вопросе, и я не согласен с тем, что «Не имеет смысла спрашивать «какова реализация>> для Apply» с вашей перефразировкой.

4. @KenSmooth документация означает, что вы можете использовать std::ops::Shr , например, для перегрузки >> , std::ops::Add для перегрузки , std::ops::Deref для перегрузки и т.д. * Вы можете использовать определенные черты для перегрузки операторов по типам

5. Это невозможно даже с помощью макроса? Оператор слишком длинный на <T>T