如何在结构中存储闭包对象?
How can I store a closure object in a struct?
我不知道如何在结构中存储闭包对象。闭包对象的参数和 return 是已知的。这是我的压缩代码:
struct Instr<F>
where F: Fn([i32;4],[i32;3]) -> [i32;4]
{
name: String,
op: F
}
fn main()
{
// Simple example showing the difficulty:
let tmp : Instr<Fn([i32;4],[i32;3]) -> [i32;4]> = Instr { name: "asd".to_string(), op: |a,b| a};
// What I really want is something more like this:
// let instrs = vec![
// Instr { name: "asdf", op: |a,b| a },
// Instr { name: "qwer", op: |a,b| a }
// ];
}
坦率地说,我不明白这些错误是什么意思。在我看来这很简单。闭包有一个类型和一个已知的大小。将它存储在相同类型的类型化字段中应该很简单。对吗?
按照错误消息的建议尝试添加 F: ?Sized
并不能修复“编译时大小未知”错误。
有人可以帮我正确编译吗?
error[E0277]: the size for values of type `dyn Fn([i32; 4], [i32; 3]) -> [i32; 4]` cannot be known at compilation time
--> a.rs:11:15
|
1 | struct Instr<F>
| - required by this bound in `Instr`
...
11 | let tmp : Instr<Fn([i32;4],[i32;3]) -> [i32;4]> = Instr { name: "asd".to_string(), op: |a,b| a};
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn Fn([i32; 4], [i32; 3]) -> [i32; 4]`
help: you could relax the implicit `Sized` bound on `F` if it were used through indirection like `&F` or `Box<F>`
--> a.rs:1:14
|
1 | struct Instr<F>
| ^ this could be changed to `F: ?Sized`...
2 | where F : Fn([i32;4],[i32;3]) -> [i32;4]
| - ...if indirection was used here: `Box<F>`
...
5 | op : F
| - ...if indirection was used here: `Box<F>`
error[E0277]: the size for values of type `dyn Fn([i32; 4], [i32; 3]) -> [i32; 4]` cannot be known at compilation time
--> a.rs:11:55
|
1 | / struct Instr<F>
2 | | where F : Fn([i32;4],[i32;3]) -> [i32;4]
3 | | {
4 | | name : String,
5 | | op : F
6 | | }
| |_- required by `Instr`
...
11 | let tmp : Instr<Fn([i32;4],[i32;3]) -> [i32;4]> = Instr { name: "asd".to_string(), op: |a,b| a};
| ^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn Fn([i32; 4], [i32; 3]) -> [i32; 4]`
error[E0308]: mismatched types
--> a.rs:11:92
|
11 | let tmp : Instr<Fn([i32;4],[i32;3]) -> [i32;4]> = Instr { name: "asd".to_string(), op: |a,b| a};
| ^^^^^^^ expected trait object `dyn Fn`, found closure
|
= note: expected trait object `dyn Fn([i32; 4], [i32; 3]) -> [i32; 4]`
found closure `[closure@a.rs:11:92: 11:99]`
不同的闭包有不同的大小,所以你不能在结构中存储“原始闭包”或“原始特征对象”,它们必须在指针后面,所以你可以将它们放在 Box
之类的所以:
struct Instr {
name: String,
op: Box<dyn Fn([i32; 4], [i32; 3]) -> [i32; 4]>,
}
fn main() {
let instrs = vec![
Instr { name: "asdf".into(), op: Box::new(|a,b| a) },
Instr { name: "qwer".into(), op: Box::new(|a,b| a) }
];
}
已接受的答案完美地解决了您的用例的解决方案,但我想澄清一下“未确定大小”的错误消息以及“简单示例”无法正常工作的问题。
Rust 完全能够按照问题中的定义将闭包存储在 Instr
中,但是您的类型规范混淆了它。每个闭包的类型都是anonymous,你不能命名。您尝试通过拼写特征 Fn(ARGS...) -> RESULT
来指定闭包类型是错误的,因为在 Rust 中,当您在需要类型的地方使用特征时,它指的是特征的动态实现,又名 trait object.它是未确定大小的特征对象,必须通过引用或智能指针访问。
因此,如果让 Rust 推断其类型,您 可以 创建一个带有任意闭包的 Instr
:
struct Instr<F>
where F: Fn([i32;4],[i32;3]) -> [i32;4]
{
name: String,
op: F
}
fn main()
{
// Simple example
let tmp : Instr<_> = Instr { name: "asd".to_string(), op: |a,b| a};
}
但这不允许您创建每个具有不同闭包的 Instr
的矢量,因为这些 Instr
将具有不同的类型。为此,您需要使用参考或 Box
,如已接受的答案所示。
我不知道如何在结构中存储闭包对象。闭包对象的参数和 return 是已知的。这是我的压缩代码:
struct Instr<F>
where F: Fn([i32;4],[i32;3]) -> [i32;4]
{
name: String,
op: F
}
fn main()
{
// Simple example showing the difficulty:
let tmp : Instr<Fn([i32;4],[i32;3]) -> [i32;4]> = Instr { name: "asd".to_string(), op: |a,b| a};
// What I really want is something more like this:
// let instrs = vec![
// Instr { name: "asdf", op: |a,b| a },
// Instr { name: "qwer", op: |a,b| a }
// ];
}
坦率地说,我不明白这些错误是什么意思。在我看来这很简单。闭包有一个类型和一个已知的大小。将它存储在相同类型的类型化字段中应该很简单。对吗?
按照错误消息的建议尝试添加 F: ?Sized
并不能修复“编译时大小未知”错误。
有人可以帮我正确编译吗?
error[E0277]: the size for values of type `dyn Fn([i32; 4], [i32; 3]) -> [i32; 4]` cannot be known at compilation time
--> a.rs:11:15
|
1 | struct Instr<F>
| - required by this bound in `Instr`
...
11 | let tmp : Instr<Fn([i32;4],[i32;3]) -> [i32;4]> = Instr { name: "asd".to_string(), op: |a,b| a};
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn Fn([i32; 4], [i32; 3]) -> [i32; 4]`
help: you could relax the implicit `Sized` bound on `F` if it were used through indirection like `&F` or `Box<F>`
--> a.rs:1:14
|
1 | struct Instr<F>
| ^ this could be changed to `F: ?Sized`...
2 | where F : Fn([i32;4],[i32;3]) -> [i32;4]
| - ...if indirection was used here: `Box<F>`
...
5 | op : F
| - ...if indirection was used here: `Box<F>`
error[E0277]: the size for values of type `dyn Fn([i32; 4], [i32; 3]) -> [i32; 4]` cannot be known at compilation time
--> a.rs:11:55
|
1 | / struct Instr<F>
2 | | where F : Fn([i32;4],[i32;3]) -> [i32;4]
3 | | {
4 | | name : String,
5 | | op : F
6 | | }
| |_- required by `Instr`
...
11 | let tmp : Instr<Fn([i32;4],[i32;3]) -> [i32;4]> = Instr { name: "asd".to_string(), op: |a,b| a};
| ^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn Fn([i32; 4], [i32; 3]) -> [i32; 4]`
error[E0308]: mismatched types
--> a.rs:11:92
|
11 | let tmp : Instr<Fn([i32;4],[i32;3]) -> [i32;4]> = Instr { name: "asd".to_string(), op: |a,b| a};
| ^^^^^^^ expected trait object `dyn Fn`, found closure
|
= note: expected trait object `dyn Fn([i32; 4], [i32; 3]) -> [i32; 4]`
found closure `[closure@a.rs:11:92: 11:99]`
不同的闭包有不同的大小,所以你不能在结构中存储“原始闭包”或“原始特征对象”,它们必须在指针后面,所以你可以将它们放在 Box
之类的所以:
struct Instr {
name: String,
op: Box<dyn Fn([i32; 4], [i32; 3]) -> [i32; 4]>,
}
fn main() {
let instrs = vec![
Instr { name: "asdf".into(), op: Box::new(|a,b| a) },
Instr { name: "qwer".into(), op: Box::new(|a,b| a) }
];
}
已接受的答案完美地解决了您的用例的解决方案,但我想澄清一下“未确定大小”的错误消息以及“简单示例”无法正常工作的问题。
Rust 完全能够按照问题中的定义将闭包存储在 Instr
中,但是您的类型规范混淆了它。每个闭包的类型都是anonymous,你不能命名。您尝试通过拼写特征 Fn(ARGS...) -> RESULT
来指定闭包类型是错误的,因为在 Rust 中,当您在需要类型的地方使用特征时,它指的是特征的动态实现,又名 trait object.它是未确定大小的特征对象,必须通过引用或智能指针访问。
因此,如果让 Rust 推断其类型,您 可以 创建一个带有任意闭包的 Instr
:
struct Instr<F>
where F: Fn([i32;4],[i32;3]) -> [i32;4]
{
name: String,
op: F
}
fn main()
{
// Simple example
let tmp : Instr<_> = Instr { name: "asd".to_string(), op: |a,b| a};
}
但这不允许您创建每个具有不同闭包的 Instr
的矢量,因为这些 Instr
将具有不同的类型。为此,您需要使用参考或 Box
,如已接受的答案所示。