Problem
當有多條語句調用而又不希望寫成一個單獨的子產品(函數或者方法)時,對于普通的方法可以寫成内聯形式,避免函數調用入棧、出棧等開銷,也或者可以定義一段宏,不過宏沒有類型檢查,也沒有作用對象的概念。而當這多條語句是在定義QObject::connect連接配接某信号的槽的實作邏輯時,除了lambda表達式,好像沒有别的更好方法了。
Solution
先上一段代碼,用一個簡單的Qt自帶的QTcpSocket和QTcpServer實作一個Tcp單機收發的功能。
頭檔案MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <iostream>
#include <cstdio>
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <windows.h>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = );
~MainWindow();
private slots:
void on_BtnTcpSndData_clicked();
private:
Ui::MainWindow *ui;
QTcpServer tcpServer;
QTcpSocket socket;
};
#endif // MAINWINDOW_H
源檔案MainWindow.cpp
#include "MainWindow.h"
#include "ui_MainWindow.h"
using namespace std;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
connect(&tcpServer,&QTcpServer::newConnection,
[&](){QTcpSocket* pSocket=tcpServer.nextPendingConnection();
connect(pSocket,&QTcpSocket::readyRead,
[=](){ui->textEditTcpRcv->append(QString::fromLocal8Bit(pSocket->readAll())); });});
tcpServer.listen(QHostAddress("127.0.0.1"),);
Sleep();
socket.connectToHost("127.0.0.1",);
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_BtnTcpSndData_clicked()
{
socket.write(ui->textEditDataToSnd->toPlainText().toLocal8Bit().data());
}
注意下在pro檔案中對c++11、和network進行設定。pro檔案中添加如下2條語句。
QT += network
CONFIG += c++11
如上代碼所示,直接在構造函數中即可實作所有的TcpSocket、TcpServer建立與連接配接工作,而且将Server端接收到資料的處理邏輯也寫進去了。所有的邏輯都在下面這條語句。
connect(&tcpServer,&QTcpServer::newConnection,
[&](){QTcpSocket* pSocket=tcpServer.nextPendingConnection();
connect(pSocket,&QTcpSocket::readyRead,
[=](){ui->textEditTcpRcv->append(QString::fromLocal8Bit(pSocket->readAll())); });});
這是一個嵌套的connect連接配接操作。首先,如果Server端有新的連接配接,進入第一個lambda表達式的處理邏輯,儲存目前連接配接的套接字,将目前套接字的準備好讀的信号連接配接到最終處理的也即第二個lambda表達式。第二個lambda表示式中将目前套接字讀取的内容顯示在螢幕上。
注意tcpServer.nextPendingConnection()傳回的指針是多變的,即第一次取出是指針,未有新連接配接,再調用些函數取出的是空指針。是以需要用一個自定義的變量來進行儲存。

———————————————————————————
Appendix Qt Lambda表達式
此介紹出處http://www.aichengxu.com/view/5170676
簡單來說,Lambda函數也就是一個函數,它的文法定義如下:
[capture](parameters)mutable->return-type{statement}
1.[capture]:捕捉清單。捕捉清單總是出現在Lambda函數的開始處。實際上,[]是Lambda引出符。編譯器根據該引出符判斷接下來的代碼是否是Lambda函數。捕捉清單能夠捕捉上下文中的變量以供Lambda函數使用;
2.(parameters):參數清單。與普通函數的參數清單一緻。如果不需要參數傳遞,則可以連同括号“()”一起省略;
3.mutable:mutable修飾符。預設情況下,Lambda函數總是一個const函數,mutable可以取消其常量性。在使用該修飾符時,參數清單不可省略(即使參數為空);
4.->return-type:傳回類型。用追蹤傳回類型形式聲明函數的傳回類型。我們可以在不需要傳回值的時候也可以連同符号”->”一起省略。此外,在傳回類型明确的情況下,也可以省略該部分,讓編譯器對傳回類型進行推導;
5.{statement}:函數體。内容與普通函數一樣,不過除了可以使用參數之外,還可以使用所有捕獲的變量。
與普通函數最大的差別是,除了可以使用參數以外,Lambda函數還可以通過捕獲清單通路一些上下文中的資料。具體地,捕捉清單描述了上下文中哪些資料可以被Lambda使用,以及使用方式(以值傳遞的方式或引用傳遞的方式)。文法上,在“[]”包括起來的是捕捉清單,捕捉清單由多個捕捉項組成,并以逗号分隔。捕捉清單有以下幾種形式:
1.[var]表示值傳遞方式捕捉變量var;
2.[=]表示值傳遞方式捕捉所有父作用域的變量(包括this);
3.[&var]表示引用傳遞捕捉變量var;
4.[&]表示引用傳遞方式捕捉所有父作用域的變量(包括this);
5.[this]表示值傳遞方式捕捉目前的this指針。
上面提到了一個父作用域,也就是包含Lambda函數的語句塊,說通俗點就是包含Lambda的“{}”代碼塊。上面的捕捉清單還可以進行組合,例如:
1.[=,&a,&b]表示以引用傳遞的方式捕捉變量a和b,以值傳遞方式捕捉其它所有變量;
2.[&,a,this]表示以值傳遞的方式捕捉變量a和this,引用傳遞方式捕捉其它所有變量。
不過值得注意的是,捕捉清單不允許變量重複傳遞。
——————————————————————–保持成長! :)