I am currently learning rust and I am having trouble understanding why my code fails and how to fix it.
I want to create a function that returns another function. The second function behaviour should depend on the parameters to the first function. This function created by the first function will be used later in a third function. This third function should have a "default input function" when the users does not explicitly define the input function.
The following code compiles, but does not achieve what I want.
// This code compiles, but is useless
type RGB = [u8; 3];
type Image = Vec<RGB>;
pub fn color_image(image: Image, coloring_function: fn(f64) -> RGB) -> Image {
// apply `coloring_function` to all processed pixels of image and return it
return image;
}
pub fn color_interpolation_generator(color_start: RGB, color_end: RGB) -> fn(f64) -> RGB {
return |x: f64| -> RGB {
return [0, 0, 0];
};
}
fn main() {
let mut image: Image = vec![];
let color_interpolation_function = color_interpolation_generator([0, 0, 0], [255, 255, 255]);
image = color_image(image, color_interpolation_function);
}
The function color_interpolation_generator
should make use of its parameters to create the returned function. If I modify it in the following way I will get an error:
pub fn color_interpolation_generator(color_start: RGB, color_end: RGB) -> fn(f64) -> RGB {
return |x: f64| -> RGB {
return color_start;
};
}
Error:
expected fn pointer, found closure
|
= note: expected fn pointer `fn(f64) -> [u8; 3]`
found closure `[closure@src/main.rs:10:12: 12:6]`
note: closures can only be coerced to `fn` types if they do not capture any variables
After some searching I did some modifications and the code compiles again:
// This code does not compile
type RGB = [u8; 3];
type Image = Vec<RGB>;
pub fn color_image(image: Image, coloring_function: impl Fn(f64) -> RGB) -> Image {
// apply `coloring_function` to all processed pixels of image and return it
return image;
}
pub fn color_interpolation_generator(color_start: RGB, color_end: RGB) -> impl Fn(f64) -> RGB {
return move |x: f64| -> RGB {
let color = color_start;
return [0, 0, 0];
};
}
fn main() {
let mut image: Image = vec![];
let color_interpolation_function = color_interpolation_generator([0, 0, 0], [255, 255, 255]);
image = color_image(image, color_interpolation_function);
}
However I also want the color_function
to have a default behaviour if no function is passed. I think the correct way to achieve this is using Option
. I modify the code accordingly:
type Image = Vec<[u8; 3]>;
pub fn color_image(image: Image, coloring_function: Option<impl Fn(f64) -> [u8; 3]>) -> Image {
// apply `coloring_function` to all processed pixels of image and return it
let function = coloring_function.unwrap_or(color_interpolation_generator(
[255, 255, 255],
[255, 255, 255],
));
return image;
}
pub fn color_interpolation_generator(
color_start: [u8; 3],
color_end: [u8; 3],
) -> impl Fn(f64) -> [u8; 3] {
return move |x: f64| -> [u8; 3] {
let color = color_start;
return [0, 0, 0];
};
}
fn main() {
let mut image: Image = vec![];
let color_interpolation_function = color_interpolation_generator([0, 0, 0], [255, 255, 255]);
image = color_image(image, Some(color_interpolation_function));
}
but I get the following error:
expected type parameter `impl Fn(f64) -> [u8; 3]`, found opaque type
...
15 | ) -> impl Fn(f64) -> [u8; 3] {
| ----------------------- the found opaque type
|
= note: expected type parameter `impl Fn(f64) -> [u8; 3]`
found opaque type `impl Fn(f64)-> [u8; 3]`
I have no idea how to fix this and at this point I am not sure if what I want can be done or if my approach is completly wrong. What is the recommended way to achieve my wanted behaviour?