[英]How to refer to the type of a closure in a generic return value?
I have a struct that contains a function, let's say of type F: Fn() -> String
.我有一个包含函数的结构,比如说
F: Fn() -> String
。 And I want to initialize it in its constructor to a particular default function, which can later be overridden by the caller if they like.我想在它的构造函数中将它初始化为一个特定的默认函数,如果他们愿意,以后可以被调用者覆盖。
struct Builder<F> {
func: F,
}
fn new_builder() -> ??? {
let hello = "hello".to_owned();
Builder { func: move || hello }
}
impl<F: Fn() -> String> Builder<F> {
fn build(self) -> String {
(self.func)()
}
}
But how do I write the return type of new_builder()
, since || {}
但是我该如何写
new_builder()
的返回类型,因为|| {}
|| {}
has an anonymous type? || {}
有匿名类型? I tried with -> Builder<_>
but that fails ( playground ), and suggests a solution that's not even syntactically valid:我尝试使用
-> Builder<_>
但失败了( playground ),并提出了一个甚至在语法上都无效的解决方案:
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
--> src/lib.rs:5:29
|
5 | fn new_builder() -> Builder<_> {
| --------^-
| | |
| | not allowed in type signatures
| help: replace with the correct return type: `Builder<[closure@src/lib.rs:6:21: 6:26]>`
For more information about this error, try `rustc --explain E0121`.
I know I can solve it by making Builder
non-generic with some boxing:我知道我可以通过使用一些拳击使
Builder
非泛型来解决它:
struct Builder {
func: Box<dyn Fn() -> ()>,
}
But that incurs additional runtime overhead in the form of allocations and indirections, and might make it harder for the compiler to optimize, eg inline calls to func
.但这会以分配和间接的形式产生额外的运行时开销,并且可能会使编译器更难优化,例如对
func
的内联调用。 This workaround is plenty fast in my practical situation, but I'm still wondering if Rust lets me stick to a purely static solution here.在我的实际情况下,这种解决方法非常快,但我仍然想知道 Rust 是否让我在这里坚持使用纯静态解决方案。
Is there a way to make this work without resorting to references or boxing?有没有办法在不求助于参考或拳击的情况下完成这项工作?
The main problem here is that the type of a closure cannot be written out in code .这里的主要问题是闭包的类型不能用代码写出来。
Luckily, for exactly that reason, the impl
keyword exists for return types:幸运的是,正是由于这个原因,返回类型存在
impl
关键字:
struct Builder<F> {
func: F,
}
fn new_builder() -> Builder<impl FnOnce() -> String> {
let hello = "hello".to_owned();
Builder {
func: move || hello,
}
}
impl<F: FnOnce() -> String> Builder<F> {
fn build(self) -> String {
(self.func)()
}
}
fn main() {
let builder = new_builder();
println!("{}", builder.build());
}
Which means: "This is some unspecified type that the compiler will figure out. It's just important that this type implements FnOnce() -> String
".这意味着:“这是编译器将找出的一些未指定的类型。这种类型实现
FnOnce() -> String
很重要”。
Other functions that use new_builder
will then be able to access func
as an FnOnce() -> String
object.其他使用
new_builder
的函数将能够访问func
作为FnOnce() -> String
对象。
Also note that I had to change the type to FnOnce
because func
in your case consumes the hello
and is therefore only callable once.另请注意,我必须将类型更改为
FnOnce
因为在您的情况下func
会消耗hello
,因此只能调用一次。
Don't worry, though.不过不用担心。
impl<F: FnOnce() -> String>
also includes Fn
and FnMut
, as they are also FnOnce
implicitely. impl<F: FnOnce() -> String>
还包括Fn
和FnMut
,因为它们也是隐含的FnOnce
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.