fn apply<A, B, C, F, G>(mut f: F, a: A)
-> impl FnMut(&B) -> C // must still be `for<'r> impl FnMut(&'r B) -> C`, because that’s what filter requires
where F: FnMut(B) -> G, // must not be `for<'r> FnMut(&'r B) -> G`, because regular functions do not implement it
G: FnMut(A) -> C,
B: Copy, // for dereferencing
A: Clone {
move |b| f(*b)(a.clone()) // this must do any bridging necessary to satisfy the requirements
}
this function signature must be EXACTLY like what I wrote or it won't work> this function signature must be EXACTLY like what I wrote or it won't work
This can be seen as a feature in the sense that you can't program by luck: well, this incantation seems about right and the compiler nods its head that it understands and that means something, so it must be right.
No, it's because the function you're returning is of type FnMut(&B) -> C, but your F function is of type FnMut(B) -> G. It expects an owned value of B, but you only have a borrowed reference to a B. Just make F of type FnMut(&B) -> G and you no longer have to dereference and no longer need the restriction that B: Copy. Higher-ranked lifetime values don't have anything to do with it.
Here's the new version:
fn apply<A, B, C, F, G>(mut f: F, a: A)
-> impl FnMut(&B) -> C
where F: FnMut(&B) -> G,
G: FnMut(A) -> C,
A: Clone {
move |b| f(b)(a.clone())
} error[E0281]: type mismatch: the type `fn(_) -> _ {tool::second::<_>}` implements the trait `std::ops::FnMut<(_,)>`, but the trait `for<'r> std::ops::FnMut<(&'r _,)>` is required (expected concrete lifetime, found bound lifetime parameter
--> src\lib.rs:50:17
|
50 | .filter(apply(second, i))
| ^^^^^
|
= note: required by `apply`
error[E0271]: type mismatch resolving `for<'r> <fn(_) -> _ {tool::second::<_>} as std::ops::FnOnce<(&'r _,)>>::Output == _`
--> src\lib.rs:50:17
|
50 | .filter(apply(second, i))
| ^^^^^ expected bound lifetime parameter , found concrete lifetime
|
= note: concrete lifetime that was found is lifetime '_#11r
= note: required by `apply`
error: aborting due to 2 previous errors
error: Could not compile `fizzbuzz`. fn main() {
for i in 1..101 {
if i % 15 == 0 {
println!("FizzBuzz");
} else if i % 3 == 0 {
println!("Fizz");
} else if i % 5 == 0 {
println!("Buzz");
} else {
println!("{}", i);
}
}
}https://bitbucket.org/iopq/fizzbuzz-in-rust/src/bf4968973d73...
I hope their production code isn't like this.
If you want production code look at Rust and Servo.
.unwrap_or_else(|| i.to_string().into())
this is the only one that was too ugly to make point-freehttps://github.com/the-guitarman/rust_fizzbuzz/blob/master/s...
template<class F, class A>
auto apply(F f, A a) {
return [f=std::move(f), a=std::move(a)](auto&& b) {
return f(std::forward<dectlype(b)>(b))(a);
}
}
The forward<decltype> is an abomination and is really in need of a language based solution, but otherwise is fairly straightforward.[1] No type checking of the definition of course, only of instantiations. On the plus side, the returned function is polymorphic and can be called for all Bs that f can be called.
https://bitbucket.org/iopq/fizzbuzz-in-rust/src/bf4968973d73...
it gives an error when I use a generic `second` method from tool.rs
EDIT: Reworded it to be more specific
Your solid grasp of the language may be different or the same as my hard to write. But neither would be confused with utterly ambiguous C. The counterpart to borrowing in C would be it's antithesis in Rust, aliasing.
That said I'm on my learning curve and my opinion could change.
I appreciate the safety+performance value proposition in Rust. More cathedral, less bazaar.