天天看點

【golang-GUI開發】struct tags系統(一)

我們已經介紹了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裡省略連接配接和被連接配接對象的函數名,這裡還有幾個規則:

  1. 括号裡指定的可以是全局對象,包括導入的包裡的可見對象,例如上個例子裡的

    controller.Controller

  2. this代指目前對象的執行個體(可以了解為c++的

    this

    ,python的

    self

    占位符,或者golang的

    receiver

    )。
  3. 括号裡的内容還可以是

    this.StructField

    ,也就是對象裡的字段
  4. 對于想連接配接繼承的

    QObject

    及其派生類或是其他類的signal/slot,目前隻能使用

    this.BaseClass.method

    的形式(與auto類似),這一點作者表示會在以後改進。

“->”和“<-”以及“auto”

這三者都需要和signal/slot tag配合使用,他們都會自動connect信号和槽,但是它們也有許多不同。

  • 首先我們日常使用應該盡量使用

    singal:"signalName,auto"

    而不是

    auto(...)

    ->

    <-

    ,如果隻是為了少寫

    Connect*

    ,那麼不應使用後三者,因為除非你有大量的

    Connect*

    需要編寫,否則容易影響代碼閱讀,特别是對連接配接對象是目前類執行個體的成員函數時。
  • ->

    <-

    用于不同的對象之間進行互動,比起分散的

    Connect*

    調用,在struct tags裡聲明邏輯關系更易于維護。
  • ->

    <-

    用于連接配接已有的信号和槽,如果想複用基類或者成員變量的signal和slot,你就需要

    ->

    <-

    替代

    auto

  • 和QML互動時,也應該使用

    ->

    <-

    連接配接來自QML的signals。

客觀上這三者都能極大的簡化我們對signal/slot的實作和使用,是以根據不同的場景需求,我們需要選用合适的tags來簡化我們的開發。

下一篇文章我們将了解

constructor

這個tag,qt中的構造函數。

如果對本篇有什麼疑問或者建議,歡迎在評論中提出。

祝玩得愉快!