rust闭包

参考

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

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

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

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

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

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

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

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

最后附上一个学习闭包过程中,关于函数调用不可变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是可变的。打印地址可以看出他们的地址都不相同。

参考链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。