Go | 什麼是帶標籤的結構?
💬 簡介
在 Go 語言中,結構型別(struct
)是一種用來封裝多個資料欄位的類型。除了簡單的資料型別欄位外,Go 還支援為結構的欄位設置標籤(tags)。結構標籤是附加在結構欄位上的元資料,通常用於與外部系統(如 JSON、SQL 等)進行交互時,來指定如何序列化或反序列化資料。在這篇文章中,我們將介紹帶標籤的結構,並提供範例說明如何使用結構標籤。
圖片來源:Gophers
🔍 什麼是結構標籤?
結構標籤是附加在結構欄位上的字串,用來指定額外的元資料。標籤通常用於定義欄位在序列化或反序列化過程中的行為,最常見的應用包括 JSON 序列化和資料庫欄位對應。標籤的格式通常是一個鍵值對,並且可以指定多個選項。
結構標籤語法
結構標籤的語法格式如下:
1 | FieldName Type `key:"value" key2:"value2"` |
FieldName
是欄位名稱。Type
是欄位的資料型別。標籤用反引號(`)包住,並且每個標籤由一組鍵值對組成。
範例:帶標籤的結構
1
2
3
4
5
6
7
8
9
10
11
12
13package main
import "fmt"
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
p := Person{"Alice", 30}
fmt.Println(p)
}📝 在這個範例中,
Person
結構有兩個欄位Name
和Age
,並且為它們分別指定了 JSON 序列化的標籤json:"name"
和json:"age"
。這表示當我們將這個結構轉換成 JSON 時,這些欄位將被映射為"name"
和"age"
。
🛠 常見的結構標籤應用
1️⃣ JSON 標籤
最常見的結構標籤應用是 JSON 序列化。在 Go 中,encoding/json
包使用結構標籤來控制欄位在 JSON 中的名稱。
- 範例:使用 JSON 標籤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"full_name"`
Age int `json:"age"`
}
func main() {
p := Person{"Alice", 30}
jsonData, err := json.Marshal(p)
if err != nil {
fmt.Println("Error marshaling JSON:", err)
return
}
fmt.Println(string(jsonData)) // 輸出: {"full_name":"Alice","age":30}
}📝 在這個範例中,
Person
結構的Name
欄位被標註為json:"full_name"
,這意味著當結構轉換為 JSON 時,Name
欄位將被轉換為"full_name"
。
2️⃣ SQL 標籤
結構標籤還可以用來與資料庫欄位進行對應。在 Go 中,許多資料庫操作庫(如 gorm
)使用結構標籤來映射資料庫欄位與 Go 結構欄位。
- 範例:使用 SQL 標籤
1
2
3
4
5
6
7
8
9
10
11
12
13
14package main
import "fmt"
type Person struct {
ID int `gorm:"primaryKey"`
Name string `gorm:"size:100"`
Age int `gorm:"default:18"`
}
func main() {
p := Person{ID: 1, Name: "Alice", Age: 30}
fmt.Println(p)
}📝 在這個範例中,我們為
Person
結構欄位添加了gorm
標籤。gorm:"primaryKey"
表示ID
是主鍵,gorm:"size:100"
表示Name
欄位的最大長度為100
,gorm:"default:18"
設定了Age
欄位的預設值。
3️⃣ 自定義標籤
除了內建的標籤庫,Go 還支持使用自定義標籤。這些標籤可以用來提供額外的元資料,並且可以在應用中進行處理。
- 範例:使用自定義標籤
1
2
3
4
5
6
7
8
9
10
11
12
13package main
import "fmt"
type Person struct {
Name string `myTag:"This is a name"`
Age int `myTag:"This is an age"`
}
func main() {
p := Person{"Alice", 30}
fmt.Println(p)
}📝 在這個範例中,我們使用了名為
myTag
的自定義標籤。這樣的標籤通常不會直接影響 Go 語言本身的行為,但可以用於其他目的,如文件生成、配置等。
🚀 應用場景
結構標籤的應用場景非常廣泛,尤其在與外部系統進行資料交互時,常常需要根據具體要求來設置結構標籤。
1️⃣ 資料序列化與反序列化
當你需要將 Go 結構轉換為 JSON、XML 或其他格式時,結構標籤非常有用。這樣你可以控制結構中的欄位如何被轉換為對應的格式。例如,在 Web 開發中,API 請求和響應通常使用 JSON 格式,這時候就需要設置適當的 JSON 標籤。
2️⃣ 資料庫操作
許多 ORM(對象關聯映射)庫(如 GORM)依賴結構標籤來定義如何將 Go 結構映射到資料庫表格中。這樣你可以指定欄位名稱、資料類型、約束條件等。
3️⃣ 配置和文件
在某些情況下,結構標籤可以用來儲存配置選項或文件說明。這對於設置自動化工具、生成程式碼或其他元資料的場景非常有用。
- 常見的實際應用情境:
- 資料驗證:例如,使用結構標籤來定義資料驗證規則。
- 配置生成:某些框架可能會根據結構標籤來生成配置或進行自動化處理。
- API 生成:可以使用自定義標籤來生成 API 文件或處理某些特定的行為
- 範例:使用自定義標籤來進行資料驗證
假設我們有一個結構,並且使用自定義標籤來定義一些驗證規則,然後我們可以寫一個工具來解析這些標籤並執行相應的驗證。輸出:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37package main
import (
"fmt"
"reflect"
"strings"
)
type Person struct {
Name string `validate:"nonempty"`
Age int `validate:"positive"`
}
func validateStruct(s interface{}) {
val := reflect.ValueOf(s)
if val.Kind() == reflect.Struct {
for i := 0; i < val.NumField(); i++ {
field := val.Field(i)
tag := val.Type().Field(i).Tag.Get("validate")
// 處理 nonempty 標籤
if tag == "nonempty" && field.String() == "" {
fmt.Println("Field", val.Type().Field(i).Name, "cannot be empty")
}
// 處理 positive 標籤
if tag == "positive" && field.Int() <= 0 {
fmt.Println("Field", val.Type().Field(i).Name, "must be positive")
}
}
}
}
func main() {
p := Person{"", -1}
validateStruct(p)
}1
2Field Name cannot be empty
Field Age must be positive📝 在這個例子中,
validate
標籤被定義為nonempty
和positive
,並且我們使用reflect
來解析這些標籤。當Name
是空字符串,或者Age
是負數時,會顯示錯誤信息。
📝 這就是一個自定義標籤的應用。標籤本身不會執行任何操作,需由程式碼(比如validateStruct
函式)來解析和根據標籤執行具體的業務邏輯。
- 範例:使用自定義標籤來進行資料驗證
🔄 補充:標籤是如何工作的?
Go 本身不會自動解析這些標籤,必須通過反射(reflection)來手動解析標籤,或者通過使用一些外部框架來進行自動解析。
反射解析標籤
1 | package main |
📝 這段程式碼會輸出結構中每個欄位的名稱和對應的標籤:
輸出:
1 | Name json:"name" |
通過這樣的反射機制,我們可以自動提取標籤並根據它們執行不同的邏輯。
⚠️ 注意事項
- 標籤的格式:結構標籤應符合一定的格式,通常由鍵值對組成。標籤的格式要符合預期的解析規則。
- 多個標籤:一個欄位可以有多個標籤,這些標籤可以用空格分開。例如,
json:"name" xml:"name" db:"name"
。 - 標籤不影響邏輯:結構標籤本身不會改變程式邏輯,它只是附加的元資料,用來輔助操作。作。
🎯 總結
- 結構標籤為 Go 語言的結構欄位提供了額外的元資料。
- 常見的應用場景包括 JSON 序列化、資料庫欄位映射和自定義配置。
- 標籤可以幫助你更靈活地處理資料和與外部系統進行交互。
最後建議回顧一下 Go | 菜鳥教學 目錄,了解其章節內容。
註:以上參考了
Go/)