I'm trying to overload the right shift operator (>>
) in rust to implement a Maybe bind.
enum Maybe<T> {
Nothing,
Just(T)
}
/// Maybe bind. For example:
///
/// ```
/// Just(1) >> |x| Just(1 + x) >> |x| Just(x * 2)
/// ```
impl<'a, T, U> Shr<|&T|: 'a -> Maybe<U>, Maybe<U>> for Maybe<T> {
fn shr(&self, f: &|&T| -> Maybe<U>) -> Maybe<U> {
match *self {
Nothing => Nothing,
Just(ref x) => (*f)(x)
}
}
}
fn main() {}
However, I'm running into an error trying to invoke the closure:
<anon>:15:28: 15:32 error: closure invocation in a `&` reference
<anon>:15 Just(ref x) => (*f)(x)
^~~~
error: aborting due to previous error
playpen: application terminated with error code 101
Program ended.
Why is it erroneous to invoke a borrowed closure, and how can I resolve the issue and implement the bind?
I found a similar question on stackoverflow, but rust has changed enough since then so that it no longer works.
Overloading the shift-right operator is not a good idea here because of various limitations it imposes on you. It takes everything by reference, whereas what you want is to take everything by value.
It is not possible to call a closure through an immutable reference; you must have a mutable reference to call it, because it may mutate its environment.
The solution in the time of the question you referred to was to use &fn(&A) -> B
, which was an immutable closure; at present we do not have that type; |&A| -> B
is parallel to &mut fn(&A) -> B
from that time, which simply can’t work because it is being done through an immutable reference. The sensible thing, of course, is to take self
by value and have the function as |A| -> B
; this is what Option.and_then
, which is exactly what you are trying to implement, does.
In short, what you are trying to do is currently impossible, though it might become possible again at some point in the future. Use a regular method instead of trying to overload the operator.
Or just use Option
, already there:
Some(1i).and_then(|x| Some(1 + x))
.and_then(|x| Some(x * 2))
This is possible nowadays. Shr
takes by value, and there are unboxed closures:
use std::ops::Shr;
use Maybe::{Nothing,Just};
#[derive(Debug)]
enum Maybe<T> {
Nothing,
Just(T)
}
impl<T, U, F> Shr<F> for Maybe<T>
where F: FnOnce(T) -> Maybe<U>
{
type Output = Maybe<U>;
fn shr(self, f: F) -> Maybe<U> {
match self {
Nothing => Nothing,
Just(x) => f(x)
}
}
}
fn main() {
let a = Just(1u8);
let b = a >> |v: u8| Just(v + 1);
println!("{:?}", b)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With