【Qt/C++】深入理解 Lambda 表達式與 mutable
關鍵字的使用
在 Qt 開發中,我們常常會用到 lambda
表達式來編寫簡潔的槽函數。今天通過一個實際代碼示例,詳細講解 lambda
的語法、變量捕獲方式,特別是 mutable
的作用。
示例代碼
QPushButton * myBtn = new QPushButton(this);
QPushButton * myBtn2 = new QPushButton(this);
myBtn2->move(100, 100);
int m = 10;connect(myBtn, &QPushButton::clicked, this, [m]() mutable {m = 100 + 10;qDebug() << m;
});connect(myBtn2, &QPushButton::clicked, this, [=]() {qDebug() << m;
});qDebug() << m;
一、Lambda 表達式基本結構
Lambda 表達式的完整語法如下:
[capture](parameter_list) mutable -> return_type {// function body
};
每個部分含義如下:
[capture]
:捕獲列表,決定 lambda 能訪問哪些外部變量以及如何訪問;(parameter_list)
:傳入 lambda 的參數;mutable
(可選):允許修改捕獲的變量副本;-> return_type
(可選):指定返回類型;{ ... }
:函數體。
二、示例中的捕獲方式說明
connect(myBtn, ..., [m]() mutable {...})
[m]
表示 按值捕獲 變量m
。lambda 拿到的是m
的拷貝;mutable
關鍵字允許修改這個拷貝,否則按值捕獲的變量在 lambda 中默認是const
的;- 這段代碼中,
m = 100 + 10;
是合法的,因為mutable
去除了m
的只讀限制; - 需要注意,這種修改只作用在拷貝上,不影響外部的
m
。
connect(myBtn2, ..., [=]() {...})
[=]
表示 按值捕獲所有外部變量;- 沒有加
mutable
,所以 lambda 內部對m
是只讀的; qDebug() << m;
打印的是外部m
的原始值,即10
。
三、mutable
的關鍵作用
默認情況下,按值捕獲的變量在 lambda 中是 const
的:
int x = 5;
auto func = [x]() {x = 10; // 編譯錯誤!x 是 const
};
加上 mutable
后就允許修改:
int x = 5;
auto func = [x]() mutable {x = 10; // 合法,修改的是 x 的副本
};
這在一些涉及臨時變量處理的場景中非常有用,尤其是在 Qt 信號槽連接中修改狀態時。
四、輸出結果分析
假設用戶點擊了 myBtn
和 myBtn2
:
-
qDebug() << m;
最初輸出10
; -
點擊
myBtn
:- 輸出
110
,是 lambda 拷貝的m
被修改;
- 輸出
-
點擊
myBtn2
:- 輸出
10
,lambda 看到的仍是最初的m
值,因為它是按值捕獲的; - 沒有使用
mutable
,無法修改。
- 輸出
五、最佳實踐建議
- 若只需要讀取變量,推薦用
[=]
捕獲; - 若要修改變量拷貝,用
[x] mutable
; - 若想修改外部變量本體,使用 引用捕獲
[&x]
; - 警惕
[&]
捕獲所有變量引用,雖然方便但易引發生命周期錯誤。
總結
捕獲方式 | 說明 | 可修改? | 是否影響外部變量 |
---|---|---|---|
[m] | 按值捕獲變量 m | ? 默認不可以 ? 使用 mutable | ? 不影響 |
[=] | 按值捕獲所有變量 | ? | ? |
[&m] | 引用捕獲變量 m | ? | ? |
[&] | 引用捕獲所有變量 | ? | ? |
通過這個例子,希望你能對 lambda
表達式的使用和 mutable
關鍵字有更深入的理解,特別是在 Qt 的信號槽連接中,lambda
是一種高效優雅的解決方案。