A
是一个包含B
向量的结构。 A
实现了add_b
方法,该方法将B
实例添加到B
列表中。 B
包含闭包属性f
。
如果我使用B
向向量添加一个add_b
,则可以。如果我用add_b
添加两个向量,我得到一个错误,说两个闭包是不同的。这是一个最小的例子:
// A struct...
struct A<F> {
b_vec: Vec<B<F>>, // A vector of B
}
// ...and its implementation
impl<F> A<F>
where
F: Fn(),
{
fn new() -> A<F> {
A { b_vec: Vec::new() }
}
fn add_b(&mut self, b: B<F>) {
self.b_vec.push(b);
}
}
// B struct...
struct B<F> {
f: F,
}
// ...and its implementation
impl<F> B<F>
where
F: Fn(),
{
fn new(f: F) -> B<F> {
B { f: f }
}
}
// I add two B (with their closures arguments) in A
fn main() {
let mut a = A::new();
a.add_b(B::new(|| println!("test")));
a.add_b(B::new(|| println!("test2")));
}
此代码导致:
error[E0308]: mismatched types
--> src/main.rs:39:20
|
39 | a.add_b(B::new(|| println!("test2")));
| ^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
|
如何将多个B
的不同闭包添加到A
的{{1}}?
答案 0 :(得分:7)
总是值得一看完整编译器输出:
error[E0308]: mismatched types
--> src/main.rs:39:20
|
39 | a.add_b(B::new(|| println!("test2")));
| ^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
|
= note: expected type `[closure@src/main.rs:38:20: 38:39]`
found type `[closure@src/main.rs:39:20: 39:40]`
= note: no two closures, even if identical, have the same type
= help: consider boxing your closure and/or using it as a trait object
特别有帮助:
没有两个闭包,即使相同,也有相同的类型
考虑装箱闭合和/或将其用作特质对象
我们可以通过完全删除类型B
来进一步简化您的示例。然后唯一的任务是保存闭包矢量。正如编译器告诉我们的那样,没有两个闭包具有相同的类型,但Vec
是一个同构数据结构,这意味着它中的每个项都具有相同的类型。
我们可以通过引入一个间接层来解决这个限制。正如编译器所建议的那样,这可以通过特征对象或装箱(后者包括第一种)来完成。相应的类型如下所示:
Vec<&Fn()>
(对特质对象的引用)Vec<Box<Fn()>>
(盒子中的特质对象)在您的示例中,您希望拥有所有闭包,因此正确的选择是选中所有闭包,因为Box<T>
是一个拥有的包装器,而引用只是借用东西。
一个完全有效的例子:
struct A {
b_vec: Vec<B>,
}
impl A {
fn new() -> A {
A { b_vec: Vec::new() }
}
fn add_b(&mut self, b: B) {
self.b_vec.push(b);
}
}
struct B {
f: Box<Fn()>,
}
impl B {
fn new<F>(f: F) -> B
where
F: Fn() + 'static,
{
B { f: Box::new(f) }
}
}
fn main() {
let mut a = A::new();
a.add_b(B::new(|| println!("test")));
a.add_b(B::new(|| println!("test2")));
}
答案 1 :(得分:3)
在此特定示例中,可以通过使用函数指针来避免特征对象:
struct B {
f: fn(),
}
impl B {
fn new(f: fn()) -> B {
B { f: f }
}
}
Lukas Kalbertodt's answer的其余部分保持不变:
struct A {
b_vec: Vec<B>,
}
impl A {
fn new() -> A {
A { b_vec: Vec::new() }
}
fn add_b(&mut self, b: B) {
self.b_vec.push(b);
}
}
fn main() {
let mut a = A::new();
a.add_b(B::new(|| println!("test")));
a.add_b(B::new(|| println!("test2")));
}
这仅是有效的,因为您的闭包无法捕获任何环境。因此,Rust编译器能够将它们“提升”为完整功能,然后引用隐式功能。