参数类型`T`可能不够长 [英] The parameter type `T` may not live long enough
问题描述
我在一个较小的脚本中重现了这个错误:
我试图在Rust中编写一个小程序,但我无法完成工作。 p>
fn main(){
let name = String :: from(World);
let test = simple(name);
println!(Hello {}!,test())
}
fn simple< T>(a:T) - >方框< Fn() - > T> {
Box :: new(move || - > T {
a
})
}
当我编译它时,出现这个错误:
错误[E0310]:参数类型`T`可能不够长
- > test.rs:8:9
|
7 |简单< T>(a:T) - >方框< Fn() - > T> {
| - help:考虑添加一个明确的生命周期限制`T:'static` ...
8 | / Box :: new(move || - > T {
9 | | a
10 | |})
| | __________ ^
|
注意:...因此`[closure@test.rs:8:18:1010 a:T]`将满足其所需的使用期限
- > test.rs:8:9
|
8 | / Box :: new(move || - > T {
9 | | a
10 | |})
| | __________ ^
我试图添加一个明确的生存期界限 T:'
如错误提示,但我得到一个新的错误: >错误[E0507]:不能移出捕获的外部变量在'Fn`中关闭
- > test.rs:9:13
|
7 | fn简单< T:'static>(a:T) - >方框< Fn() - > T> {
| - 捕获的外部变量
8 | Box :: new(move || - > T {
9 | a
| ^)不能从捕获的外部变量中移出`Fn`闭包
在这里有一些事情发生,这一切都与移动语义上的一些小尴尬有关首先,简单的
函数不需要为它的 T
参数。从函数的角度来看, T
可以是任何类型,这意味着它可以是一个因为它需要有一个生命周期,Lifetime elision不适用于这种情况,所以你需要明确写出它。编译器建议'static
,这很好如果你有更复杂的生命周期,你需要使用一个生命周期参数;见下面的例子获取更多信息。
你的关闭不能是一个 Fn
,因为你不能多次调用它,因为新的错误你已经说过了,当它被调用时,你的闭包将它捕获的值( a
)移出闭包。这和说& self
的方法是一样的。如果函数调用是一种常规方法,而不是特殊的语法,它可能是这样的:
特质FnOnce {
类型输出
fn call(self) - >输出
}
特性Fn:FnOnce {
fn call(& self) - >输出
}
//生成的类型
struct MyClosure< T> {
a:T
}
impl< T> FnOnce for MyClosure< T> {
fn call(self) - > T {self.a}
}
(这并不比实际的简单)
所以简而言之,一个消耗捕获值的闭包不会实现 Fn
,只有 FnOnce
。调用它会消耗闭包。还有一个 FnMut
,但在这里没有关系。
这还有一个含义,就是当它们移动时消耗值。您可能已经注意到,您无法调用任何trait对象( Box< T>
)上的 self
其中 T
是特质)。要移动一个对象,移动它的代码需要知道被移动对象的大小。对未特化的特征对象不会发生这种情况。这也适用于 Box< FnOnce>
。由于调用闭包会移动它(因为调用是 self
方法),所以不能调用闭包。
<那么如何解决这个问题呢?它使得
Box< FnOnce>
有点无用。有两种选择。 如果你可以使用unstable Rust,你可以使用 另一种可能是更广泛适用的工程解决方案的替代方案是避免移出关闭。 如果您始终将静态对象放入闭包中,您可以返回一个引用 如果对象不是静态的,你可以返回一个 你可以让闭包复制它的参数给每个调用者。这样可以根据需要调用多次,每个调用者都可以获得自己的副本。不需要进一步的终身管理。如果以这种方式实现它,则仍然可以使用 I'm trying to write a small program in Rust but I can't get it work. I have reproduced the error in a smaller script: When I compile it, I get this error: I have tried to add an explicit lifetime bound
There's a couple of things going on here, and it all has to do with a slight awkwardness around move semantics and closures. First off, the Your closure can't be a (This is not that much simpler than the actual definitions of these types.) So in short, a closure that consumes its captured values doesn't implement This has another implication, to do with consuming values when they're moved. You might have noticed that you can't call a method that takes So how to get around this problem? It makes If you can use unstable Rust, you can use the An alternative that might be a more broadly applicable engineering solution would be to avoid moving out of the closure. You could return a reference If the object isn't static, you could instead return a You could have the closure copy its argument to each caller. This way it could be called as many times as necessary and each caller would get its own copy. No further lifetime management would be necessary. If you implement it this way, you can still make the argument an 这篇关于参数类型`T`可能不够长的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! FnBox
类型:它替代 FnOnce
在 Box
内工作。它隐藏在功能门的后面,因为,正如文档警告你:请注意,如果 Box< FnOnce()>将来可能会弃用
闭包变得可以直接使用。 这里有一个使用这个解决方案的游乐场,它增加了生命周期参数来解决原来的问题。 / b> FnBox
;
&'static T
这样,您可以随意调用闭包,并且所有调用者都可以获得对同一个对象的引用。
Rc< T>
。在这种情况下,所有调用者仍然可以获得对同一对象的引用,并且该对象的生命周期是动态管理的,因此只要需要,它就会保持活动状态。 这是另一个实施此选项的场地。
Rc
而不是 T
来使用参数该功能与上述选项相同。
fn main() {
let name = String::from("World");
let test = simple(name);
println!("Hello {}!", test())
}
fn simple<T>(a: T) -> Box<Fn() -> T> {
Box::new(move || -> T {
a
})
}
error[E0310]: the parameter type `T` may not live long enough
--> test.rs:8:9
|
7 | fn simple<T>(a: T) -> Box<Fn() -> T> {
| - help: consider adding an explicit lifetime bound `T: 'static`...
8 | / Box::new(move || -> T {
9 | | a
10 | | })
| |__________^
|
note: ...so that the type `[closure@test.rs:8:18: 10:10 a:T]` will meet its required lifetime bounds
--> test.rs:8:9
|
8 | / Box::new(move || -> T {
9 | | a
10 | | })
| |__________^
T: 'static
as suggested by the error but I get a new error:error[E0507]: cannot move out of captured outer variable in an `Fn` closure
--> test.rs:9:13
|
7 | fn simple<T: 'static>(a: T) -> Box<Fn() -> T> {
| - captured outer variable
8 | Box::new(move || -> T {
9 | a
| ^ cannot move out of captured outer variable in an `Fn` closure
simple
function does need to specify a lifetime for its T
parameter. From the function's point of view, T
can be any type, which means it could be a reference, so it needs to have a lifetime. Lifetime elision doesn't apply to this case so you need to write it out explicitly. The compiler suggests 'static
, which is fine for a hello world. If you had more complex lifetimes, you'd need to use a lifetime parameter; see my example below for more.Fn
, because you can't call it more than once. As the new error you've got says, your closure moves the value it captures (a
) out of the closure when it's called. That's the same thing as saying it's a method that takes self
instead of &self
. If function calls were a normal method instead of having special syntax, it would be something like this:trait FnOnce {
type Output
fn call(self) -> Output
}
trait Fn : FnOnce {
fn call(&self) -> Output
}
// generated type
struct MyClosure<T> {
a: T
}
impl<T> FnOnce for MyClosure<T> {
fn call(self) -> T { self.a }
}
Fn
, only FnOnce
. Calling it consumes the closure. There's also a FnMut
but that's not relevant here.self
on any trait object (Box<T>
where T
is a trait). To move an object, the code that's moving it needs to know the size of the object being moved. This doesn't happen with trait objects, which are unsized. That also applies to Box<FnOnce>
. Since calling the closure moves it (because calling is a self
method`), you can't call the closure.Box<FnOnce>
a bit useless. There's two options.FnBox
type: it's a replacement for FnOnce
that works inside a Box
. It's hidden behind a feature gate because, as the documentation warns you: "Note that FnBox
may be deprecated in the future if Box<FnOnce()>
closures become directly usable." Here's a playground that uses this solution and adds lifetime parameters to fix the original problem.
&'static T
if you're always putting static objects into the closure. That way you can call the closure as many times as you like and all callers get a reference to the same object.Rc<T>
. In this case, all callers still get a reference to the same object, and the lifetime of that object is dynamically managed, so it'll stay alive as long as needed. Here's another playground implementing this option.Rc<T>
instead of a T
to use the function the same way as the option above.