Rust基礎筆記 閉包

2022-07-12 06:15:11 字數 3725 閱讀 5351

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中的閉包與其他語言有些不一樣的用法,每次看過很容易忘記,特此記錄。閉包的基本定義方法是 使用 替代 將輸入變數括起來。區塊定界符 將所有函式中的表示式擴起來,如果只有一條表示式也可以不加。閉包與函式的一大區別是,閉包能夠在內...