closure看上去是這樣的:
let plus_one = |x: i32| x + 1;
assert_eq!(2, plus_one(1));
首先建立乙個繫結plus_one,然後將它分配給乙個closure,body是乙個expression,注意 也是乙個expression。
它也可以被寫成這樣:
let plus_two = |x| ;
assert_eq!(4, plus_two(2));
fn plus_one_v1 (x: i32) -> i32
let plus_one_v2 = |x: i32| -> i32 ;
let plus_one_v3 = |x: i32| x + 1 ;
值得注意的是在closure中引數和返回值的型別都是可以省略的,下面這種形式也是可以的:
let plus_one = |x| x + 1;
乙個小例子:
let num = 5;
let plus_num = |x: i32| x + num;
assert_eq!(10, plus_num(5));
也就是說,plus_num引用了乙個在它作用於中的變數num,具體地說這是乙個borrow,它滿足所有權系統的要求,來看乙個錯誤的例子:
let mut num = 5;
let plus_num = |x: i32| x + num;
let y = &mut num;
error: cannot borrow `num` as mutable because it is also borrowed as immutable
let y = &mut num;
^~~
在上面的**中,plus_num已經對num做了不可變引用,而在plus_one的作用域內,又發生了一次可變引用,所以就違反了所有權系統中的如下規則:
如果對乙個繫結進行了不可變引用,那麼在該引用未超出作用域之前,不可以再進行可變引用,反之也是一樣。對**做出如下修改即可:
let mut num = 5;
// plus_num goes out of scope, borrow of num ends
let y = &mut num;
再看乙個例子:
let nums = vec![1, 2, 3];
let takes_nums = || nums;
println!("", nums);
有問題嗎?
有,而且是大問題,編譯器的報錯如下:
closure.rs:8:19: 8:23 error: use of moved value: `nums` [e0382]
closure.rs:8 println!("", nums);
從錯誤中可以看出來,在最後乙個輸出語句中,nums已經沒有對資源 vec![1, 2, 3] 的 所有權了,該資源的所有權已經被move到了closure中去了。
那麼問題來了:
為什麼在前面的例子中closure是borrow,而到了這裡就變成了move了呢?
我們從頭梳理一遍:
let mut num = 5;
let plus_num = || num + 1;
let num2 = &mut num;
error:
closure.rs:5:21: 5:24 error: cannot borrow `num` as mutable because it is also borrowed as immutable
closure.rs:5 let num2 = &mut num;
說明在closure中發生了immutable borrow,這樣才會和下面的&mut衝突,現在我們來做乙個改動:
let plus_num = || num + 1;
// 改成如下語句
let mut plue_num = || num += 1;
再編譯一次:
error:
closure.rs:4:17: 4:20 error: cannot borrow `num` as mutable more than once at a time
closure.rs:4 let num2 = &mut num;
可以發現,在closure中發生了mutable borrow,為什麼會這樣呢?
在closure無非就是這3種情況:
let plus_num = || num + 1; // 這個只需要引用即可,所以plus_num型別為fn()
let mut plue_num = || num += 1; // 這個則需要&mut t,所以plus_num型別為fnmut()
// 這是手冊裡的乙個例子
// 這是乙個沒有實現copy trait的型別
let movable = box::new(3);
// `drop` 需要型別t,所以closure環境就需要 by value t.,所以consume型別為fnonce()
let consume = || ;
// 所以這個consume只能執行一次
consume();
有一點要注意的是:
在前面的例子應該分成兩類:
let a= 100i32;
let a = vec![1,2,3];
區別就是i32型別實現了copy trait,而vector沒有!!!
參考:使用move關鍵字,強制closure獲得所有權,但下面的例子得注意一下:
let num = 5;
let owns_num = move |x: i32| x + num;
儘管這裡使用move,變數遵循move語義,但是,在這裡5實現了copy,所以owns_own獲得的是 5 的拷貝的所有權,有什麼區別呢?
來看看這段**:
let mut num = 5;
assert_eq!(10, num);
這段**得到的是我們想要的結果,但是如果我們加上move關鍵字呢?上面的**就會報錯,因為num的值仍是 5 ,並沒有發生改變,
為什麼呢?
上面說到了,move強制閉包環境獲得所有權,但是 5 實現了copy,所以閉包獲得的是其拷貝的所有權,同理閉包中修改的也是 5 的拷貝。
在rust中閉包的概念並不好理解,因為牽扯到了太多所有權的概念,可以先把所有權弄懂了,閉包也就好理解了。 rust筆記13 閉包
閉包是乙個可捕獲周圍環境的可執行 片段,基本的幾個定義方式如下 fn add one v1 x u32 u32 let add one v2 x u32 u32 let add one v3 x let add one v4 x x 1 內部的是捕獲的周圍的變數,預設捕獲的是不可變借用,先給出乙個實...
Rust閉包小結
rust會根據閉包體進行環境變數的捕獲,閉包捕獲環境中變數的模式優先順序順序為 不可變借用,可變借用,所有權。fn main println s 這個閉包的閉包體和上面僅有一處不同,那就是加了move,這會強行拿走s的所有權,即影響了捕獲方式。即使 閉包體看起來是用最普通的不可變引用來操作的環境中的...
rust學習 閉包 closuer
閉包就是匿名函式或者lambda表示式,由於rust的一些特殊語法,rust中的閉包與其他語言有些不一樣的用法,每次看過很容易忘記,特此記錄。閉包的基本定義方法是 使用 替代 將輸入變數括起來。區塊定界符 將所有函式中的表示式擴起來,如果只有一條表示式也可以不加。閉包與函式的一大區別是,閉包能夠在內...