无法移出Fn闭包中捕获的外部变量

时间:2018-04-24 11:23:23

标签: rust

fn make_adder(x: String) -> Box<Fn() -> String> {
    Box::new(|| x)
}

fn main() {
    make_adder(String::from("a"));
}

这会导致此错误:

error[E0507]: cannot move out of captured outer variable in an `Fn` closure
 --> src/main.rs:2:17
  |
1 | fn make_adder(x: String) -> Box<Fn() -> String> {
  |               - captured outer variable
2 |     Box::new(|| x)
  |                 ^ cannot move out of captured outer variable in an `Fn` closure

如何使其正确?

1 个答案:

答案 0 :(得分:2)

实现Fn 的闭包可以被多次调用(接收器参数是public string Decrypt(string cipherText) { string EncryptionKey = "myPassword"; cipherText = cipherText.Replace(" ", "+"); byte[] cipherBytes = Convert.FromBase64String(cipherText); using (Aes encryptor = Aes.Create()) { Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 }); encryptor.Key = pdb.GetBytes(32); encryptor.Padding = PaddingMode.None; encryptor.IV = pdb.GetBytes(16); using (MemoryStream ms = new MemoryStream()) { using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write)) { cs.Write(cipherBytes, 0, cipherBytes.Length); cs.Close(); } cipherText = Encoding.Unicode.GetString(ms.ToArray()); } } return cipherText; } ,是对闭包的不可变引用):

&self

这意味着关闭fn call_multiple_times<F: Fn(u8) -> i32>(f: F) { // Works! We can call the closure mutliple times let a = f(1); let b = f(27); let c = f(31); } ,你可以这样做:

Fn() -> String

现在你有两个let s1 = adder(); let s2 = adder(); s虽然你只开始一个!魔术?你当然可以通过克隆原始字符串获得另一个字符串,但我们不会在这里做。所以它显然无法运作。

您可以通过两种方式解决这个问题。要么你不需要多次调用你的闭包。在这种情况下,您只需将String更改为FnOnce(要求不高的特质)。只能调用Fn闭包......好吧......一次。这有效:

FnOnce

另一方面,也许您希望多次调用闭包并始终希望返回字符串的新克隆。你可以这样做:

fn make_adder(x: String) -> Box<FnOnce() -> String> {
    Box::new(|| x)
}

这里我们添加了fn make_adder(x: String) -> Box<Fn() -> String> { Box::new(move || x.clone()) } 调用(因为在Rust中,深层克隆从不隐含!)我们添加了.clone()关键字。后者是明确将字符串move移动到闭包中所必需的,而不仅仅是借用它。