我們已經介紹了qt的signal和slot,現在該講講它的struct tags系統了。qt擁有多種的struct tags,我們會去一一了解它們。
什麼是struct tags?
struct tag
又叫做結構體标簽,顧名思義,它就是用來給結構體字段做标記的。比如我們熟悉的JSON就使用了tags:
type User struct {
UserId int `json:"user_id" bson:"user_id"`
UserName string `json:"user_name" bson:"user_name"`
}
tags由反引号包裹,name在
:
之前,value在
:
之後由雙引号包裹。
有了這些tags,我們的代碼就可以很輕松的使用reflect來取得tags的name和name對應的值:
u := &User{UserId: 1, UserName: "tony"}
t := reflect.TypeOf(u)
field := t.Elem().Field(0)
fmt.Println(field.Tag.Get("json")) // "user_id"
fmt.Println(field.Tag.Get("bson")) // "user_id"
我們的qt正是依賴這一特性實作了Qt的moc系統,使用不同的tags除了可以實作signal和slot之外還能實作moc的多種功能,甚至是qt自己的一些擴充。
“->” 和 “<-”
在signal裡我們已經介紹了auto,它具有很多的局限性,項目作者也表示auto應該盡量單獨使用,不應該使用
auto(...)
的形式。而為了更友善的連接配接signal和slot,我們就需要用到
->
和
<-
了。
先看個示例,這次我們從官方的例子裡節選一段:
type Chart struct {
core.QObject
*charts.QChart
_ func() `constructor:"init"`
_ func() `slot:"handleTimeout,<-(this.m_timer.timeout)"`
}
對于槽handleTimeout,我們使用了
<-
,它和下面這句等價:
this.m_timer.ConnectTimeout(this.handleTimeout)
意思是将
this.m_timer
的Timeout信号和
this.handleTimeout
函數connect,當觸發了
this.m_timer
的Timeout信号時這個函數也會被調用。
你也可以不指定信号名稱,預設會和signal tag指定的信号名同名的函數進行connect:
_ func() `slot:"handleTimeout,<-(this.m_timer)"`
_ func() `slot:"handleTimeout,<-(this.m_timer.handleTimeout)"`
等價。
我們再來看一下
->
的使用:
import "controller"
type dialogTemplate struct {
core.QObject
_ func() `constructor:"init"`
_ func(cident string) `signal:"show,<-(controller.Controller)"`
_ func(bool) `signal:"blur,->(controller.Controller)"`
}
可以看到,我們對信号Blur使用了
->
,這個表達的含義與
<-
相反,它是将signal tag聲明的信号或是slot tag聲明的槽與
->
之後的函數進行connect,當你觸發這個信号或是調用這個槽時,括号内的函數也會被調用,等價于:
this.ConnectBlur(controller.Controller.blur)
或是(如上面所說,可以省略函數名)
this.ConnectBlur(controller.Controller)
“->”和“<-”的一些使用規則
上一段裡我們已經提到可以在這兩個tags裡省略連接配接和被連接配接對象的函數名,這裡還有幾個規則:
- 括号裡指定的可以是全局對象,包括導入的包裡的可見對象,例如上個例子裡的
。controller.Controller
- this代指目前對象的執行個體(可以了解為c++的
,python的this
占位符,或者golang的self
)。receiver
- 括号裡的内容還可以是
,也就是對象裡的字段this.StructField
- 對于想連接配接繼承的
及其派生類或是其他類的signal/slot,目前隻能使用QObject
的形式(與auto類似),這一點作者表示會在以後改進。this.BaseClass.method
“->”和“<-”以及“auto”
這三者都需要和signal/slot tag配合使用,他們都會自動connect信号和槽,但是它們也有許多不同。
- 首先我們日常使用應該盡量使用
而不是singal:"signalName,auto"
,auto(...)
或->
,如果隻是為了少寫<-
,那麼不應使用後三者,因為除非你有大量的Connect*
需要編寫,否則容易影響代碼閱讀,特别是對連接配接對象是目前類執行個體的成員函數時。Connect*
-
->
用于不同的對象之間進行互動,比起分散的<-
調用,在struct tags裡聲明邏輯關系更易于維護。Connect*
-
->
用于連接配接已有的信号和槽,如果想複用基類或者成員變量的signal和slot,你就需要<-
->
替代<-
auto
- 和QML互動時,也應該使用
->
連接配接來自QML的signals。<-
客觀上這三者都能極大的簡化我們對signal/slot的實作和使用,是以根據不同的場景需求,我們需要選用合适的tags來簡化我們的開發。
下一篇文章我們将了解
constructor
這個tag,qt中的構造函數。
如果對本篇有什麼疑問或者建議,歡迎在評論中提出。
祝玩得愉快!