如何在Rust中编写函数? [英] How to compose functions in Rust?
问题描述
我正在尝试编写一个包含两个功能的功能.最初的设计非常简单:一个函数需要两个函数并返回一个组合函数,然后我可以将其与其他函数组合起来,因为Rust没有休息参数.我碰到了令人沮丧的无用的编译器错误.
I'm trying to write a function that composes two functions. The initial design is pretty simple: a function that takes two functions and returns a composed function which I can then compose with other functions, since Rust doesn't have rest parameters. I've run into a wall built with frustrating non-helpful compiler errors.
我的撰写功能:
fn compose<'a, A, B, C, G, F>(f: F, g: G) -> Box<Fn(A) -> C + 'a>
where
F: 'a + Fn(A) -> B + Sized,
G: 'a + Fn(B) -> C + Sized,
{
Box::new(move |x| g(f(x)))
}
我想如何使用它:
fn main() {
let addAndMultiply = compose(|x| x * 2, |x| x + 2);
let divideAndSubtract = compose(|x| x / 2, |x| x - 2);
let finally = compose(*addAndMultiply, *divideAndSubtract);
println!("Result is {}", finally(10));
}
无论我怎么尝试,编译器都不喜欢这种特质界限永远不会得到满足.错误是:
The compiler doesn't like that, no matter what I try, the trait bounds are never satisfied. The error is:
error[E0277]: the size for values of type `dyn std::ops::Fn(_) -> _` cannot be known at compilation time
--> src/main.rs:13:19
|
13 | let finally = compose(*addAndMultiply, *divideAndSubtract);
| ^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `dyn std::ops::Fn(_) -> _`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
note: required by `compose`
--> src/main.rs:1:1
|
1 | / fn compose<'a, A, B, C, G, F>(f: F, g: G) -> Box<Fn(A) -> C + 'a>
2 | | where
3 | | F: 'a + Fn(A) -> B + Sized,
4 | | G: 'a + Fn(B) -> C + Sized,
5 | | {
6 | | Box::new(move |x| g(f(x)))
7 | | }
| |_^
推荐答案
@ljedrz指出工作,您只需要再次引用组成的函数:
As @ljedrz points out, to make it work you only need to reference the composed functions again:
let finally = compose(&*multiply_and_add, &*divide_and_subtract);
(请注意,在Rust中,约定规定变量名称应在snake_case中)
(Note that in Rust, convention dictates that variable names should be in snake_case)
但是,我们可以做得更好!
However, we can make this better!
从Rust 1.26开始,我们可以使用抽象返回类型(以前的功能为#![feature(conservative_impl_trait)]
).这可以帮助您大大简化示例,因为它可以跳过生存期,引用,Sized
约束和Box
es:
Since Rust 1.26, we can use abstract return types (previously featured gated as #![feature(conservative_impl_trait)]
). This can help you simplify your example greatly, as it allows you to skip the lifetimes, references, Sized
constraints and Box
es:
fn compose<A, B, C, G, F>(f: F, g: G) -> impl Fn(A) -> C
where
F: Fn(A) -> B,
G: Fn(B) -> C,
{
move |x| g(f(x))
}
fn main() {
let multiply_and_add = compose(|x| x * 2, |x| x + 2);
let divide_and_subtract = compose(|x| x / 2, |x| x - 2);
let finally = compose(multiply_and_add, divide_and_subtract);
println!("Result is {}", finally(10));
}
最后,由于您提到了rest参数,因此我怀疑您真正想要的是拥有一种以灵活的方式链式组合任意数量的函数的方法.我为此编写了此宏:
Finally, since you mention rest parameters, I suspect that what you actually want is to have a way to chain-compose as many functions as you want in a flexible manner. I wrote this macro for this purpose:
macro_rules! compose {
( $last:expr ) => { $last };
( $head:expr, $($tail:expr), +) => {
compose_two($head, compose!($($tail),+))
};
}
fn compose_two<A, B, C, G, F>(f: F, g: G) -> impl Fn(A) -> C
where
F: Fn(A) -> B,
G: Fn(B) -> C,
{
move |x| g(f(x))
}
fn main() {
let add = |x| x + 2;
let multiply = |x| x * 2;
let divide = |x| x / 2;
let intermediate = compose!(add, multiply, divide);
let subtract = |x| x - 2;
let finally = compose!(intermediate, subtract);
println!("Result is {}", finally(10));
}
这篇关于如何在Rust中编写函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!