rust闭包

rust闭包

参考

Rust有三个闭包trait:Fn、FnMut和FnOnce编译器会根据闭包内代码的行为自动为闭包实现这些trait。

上面这段话超级重要!!!

  1. 对于不可变或移动捕获变量的闭包,编译器会实现Fn trait,这样闭包可以多次调用,甚至可以在多个线程上并行调用
  2. 对于可变捕获变量但不移动它们出闭包的闭包,编译器会实现FnMut trait,这样的闭包可以多次调用,但不能并行调用
  3. 对于会移动捕获变量出闭包的闭包,编译器会实现FnOnce trait,这样的闭包只能调用一次。注意move关键字不影响trait实现,它只是强制移动变量进入闭包

Fn trait是FnMut的子trait,FnMut trait是FnOnce的子trait。这意味着:

  1. 每个实现Fn trait的闭包也实现了FnMut和FnOnce。任何需要FnMut或FnOnce的地方,都可以传递实现Fn的闭包。
  2. 每个实现FnMut trait的闭包也实现了FnOnce。任何需要FnOnce的地方都可以传递实现FnMut的闭包。

如果被调用者接受FnOnce,它对闭包能做的事情受到最大限制——它只能调用闭包一次。但是调用者可以自由传递任何闭包,因为所有的闭包都实现了FnOnce,这是由子trait和父trait的关系决定的。

如果被调用者接受FnMut,那么它对闭包的限制会少一些。现在它可以调用闭包多次,但是仍然不能例如在多个线程上并发地调用闭包,因为那会导致数据共用。相应的,调用者也会受到更多的限制。例如,它不能在闭包中drop一个被捕获的变量或以其他方式将其移出闭包。

最后,如果被调用者接受Fn,那么它可以无限制的调用闭包,甚至并发调用。与此同时,调用者不能改变闭包中的变量。
rust闭包_第1张图片

最后附上一个学习闭包过程中,关于函数调用不可变String作为形参可变String的例子。

  let a = "fox".to_string();
  let add1=&a;
  println!("{:p}",add1);  // 打印变量的地址
  let b = test1(a);
  println!("{:?}",b);
  println!("{:p}",&b);

}

fn test1(mut s : String)-> String{
  let add2 = &s;
  println!("{:p}",add2);
  s.push_str("123");
  s
}

PS D:\code\rust\test_demo> cargo run
   Compiling test_demo v0.1.0 (D:\code\rust\test_demo)
    Finished dev [unoptimized + debuginfo] target(s) in 2.51s
     Running `target\debug\test_demo.exe`
0x119a6ff3a8
0x119a6ff420
"fox123"    
0x119a6ff408

  let a = "fox".to_string();
  let add1=&a;
  println!("{:p}",add1);  // 打印变量的地址
  let b = test1(a);
  println!("{:?}",b);
  println!("{:p}",&b);

}

fn test1(s : String)-> String{
  let add2 = &s;
  println!("{:p}",add2);
  // s.push_str("123");
  s
}

PS D:\code\rust\test_demo> cargo run
   Compiling test_demo v0.1.0 (D:\code\rust\test_demo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.42s
     Running `target\debug\test_demo.exe`
0x8758aff458
0x8758aff4d0
"fox"       
0x8758aff4b8

实际上a是不可变string,但是test1函数可以捕获a的所有权,然后重新给了一个新的变量s,s是可变的。打印地址可以看出他们的地址都不相同。

你可能感兴趣的:(md,rust,java,开发语言)