我目前正在学习 Rust,但我无法理解为什么我的代码失败以及如何修复它。
我想创建一个返回另一个函数的函数。第二个函数的行为应取决于第一个函数的参数。第一个函数创建的这个函数稍后将在第三个函数中使用。当用户没有明确定义输入功能时,这第三个功能应该有一个“默认输入功能”。
以下代码可以编译,但没有达到我想要的效果。
// 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);
}
函数
color_interpolation_generator
应使用其参数来创建返回的函数。如果我按以下方式修改它,我会收到错误:
pub fn color_interpolation_generator(color_start: RGB, color_end: RGB) -> fn(f64) -> RGB {
return |x: f64| -> RGB {
return color_start;
};
}
错误:
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
经过一番搜索,我做了一些修改,代码再次编译:
// 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);
}
但是,如果没有传递函数,我也希望
color_function
有默认行为。我认为实现这一目标的正确方法是使用Option
。我相应地修改了代码:
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));
}
但我收到以下错误:
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]`
我不知道如何解决这个问题,目前我不确定我想要的是否可以完成,或者我的方法是否完全错误。实现我想要的行为的推荐方法是什么?
问题是
coloring_function
有一些(通用)类型,impl Fn(f64) -> [u8; 3]
,并且 color_interpolation_generator()
返回某种类型,impl Fn(f64) -> [u8; 3]
,并且它们是不同的类型。因此,您不能 unwrap_or
第一个的 Option
并在那里放置第二个的实例。
当您需要选择一种不同类型时,通常要做的事情是使用
Box<dyn Trait>
,在您的情况下为 Box<dyn Fn(f64) -> [u8; 3]>
。更改 color_image()
,例如:
pub fn color_image(image: Image, coloring_function: Option<Box<dyn Fn(f64) -> [u8; 3]>>) -> Image {
// apply `coloring_function` to all processed pixels of image and return it
let function = coloring_function.unwrap_or_else(|| {
Box::new(color_interpolation_generator(
[255, 255, 255],
[255, 255, 255],
))
});
return image;
}
(我将
unwrap_or()
更改为 unwrap_or_else()
以避免在存在参数时分配 Box
)。
并称其为:
image = color_image(image, Some(Box::new(color_interpolation_function)))
在 Rust 中,我只会构建一个结构体,其中包含您想要处理的所有数据,包括一些指示要调用哪些函数的 bool 值。
然后我将实现一个构造函数,它接受构建结构所需的输入参数。在此构造函数内,您可以使用传递给构造函数的参数来确定传递给从构造函数返回的结构实例的布尔值。
这为您提供了抽象,并允许您保护数据和功能的成员,仅允许其按您的意图使用。这是一个一般示例,因为我不太了解如何使用代码的上下文。构造函数使用传递给它的颜色值来确定将在公共函数内使用的 bool 值,该函数将根据 bool 是 true 还是 false 来调用两个私有函数之一。除了构造函数方法和 return_color_pallete 成员之外,所有这些成员都是私有的,并且受到保护以防止被错误使用。
struct ColorPixels {
red: i32,
green: i32,
blue: i32,
basic_colors: bool,
}
impl ColorPixels {
pub fn new(red:i32, green:i32, blue:i32) -> ColorPixels {
let basic_colors = if r+g+b < 280 {true} else {false};
ColorPixels {red, green, blue, basic_colors}
}
pub fn return_color_pallet(&self) -> Image {
if &self.basic_colors {return self.basic();} else {return self.complex();};
}
fn basic(&self) -> Image {
Image(&self.red, &self.green, &self.blue)
}
fn comlex(&self) -> {
... write some code creating variables out of your inputs modify as you see fit etc...
Image(complex_red, complex_green, complex_blue)
}