一、结构体基础

结构体 (struct) 将多个不同类型的字段集中组成一种复合类型,按声明时的字段顺序初始化。

  1. type user struct {
  2. name string
  3. age byte
  4. }
  5. user := user {"Tom", 2}

定义匿名结构体时没有 type 关键字,与其他定义类型的变量一样,如果在函数外部需在结构体变量前加上 var 关键字,在函数内部可省略 var 关键字。

  1. // 在函数外部定义匿名结构体并赋值给
  2. var config struct {
  3. APIKey string
  4. OAuthConfig oauth.Config
  5. }// 定义并初始化并赋值给
  6. datadata := struct {
  7. Title string
  8. Users []*User
  9. }{
  10. title,
  11. users
  12. }

二、匿名结构体使用场景

匿名结构体在四种常见情景下的用法。

1、组织全局变量

属于同一类的全局变量可通过匿名结构体组织在一起。

  1. var config struct {
  2. APIKey string
  3. OAuthConfig oauth.Config
  4. }
  5. config.APIKey = "BADC0C0A"

2、数据模版

可在后端把数据组织成前端需要的格式传给渲染模版

  1. package mainimport ( "html/template"
  2. "net/http"
  3. "strings")type Paste struct {
  4. Expiration string
  5. Content []byte
  6. UUID string}func pasteHandler(w http.ResponseWriter, r *http.Request) {
  7. paste_id := strings.TrimPrefix(r.URL.Path, "/paste")
  8. paste := &Paste{UUID: paste_id}
  9. keep_alive := false
  10. burn_after_reading := false
  11. data := struct {
  12. Paste *Paste
  13. KeepAlive bool
  14. BurnAfterReading bool
  15. } {
  16. paste,
  17. keep_alive,
  18. burn_after_reading,
  19. }
  20. t, _ := template.ParseFiles("templates/paste.html")
  21. t.Execute(w, data)
  22. }

匿名函授定义并初始化之后赋值给 data 变量,除了把 Paste 结构体对象的值传给前端之外,还额外添加了必要的字段。
写过前后端的同学应该知道,前端有时需要后端返回一个标志变量作为判断条件是否显示某一块内容。

  1. Expiration: {{ .Paste.Expiration }}
  2. UUID: {{ .Paste.UUID}}
  3. {{ if .BurnAfterReading }}
  4. BurnAfterReading: True{{ else }}
  5. BurnAfterReading: False{{ end }}

3、测试案例数据

在写测试代码时,经常用到匿名结构体生成用例的输入输出,为了覆盖各个测试维度,通常结合切片使用,构成了测试样例尽可能地覆盖所有可能发生情况。

  1. var indexRuneTests = []struct {
  2. s string
  3. rune rune out int}{
  4. {"a A x", 'A', 2},
  5. {"some_text=some_value", '=', 9},
  6. {"a", 'a', 3},
  7. {"ab", '', 4},
  8. }

4、嵌入式锁 (Embedded lock)

  1. var hits struct {
  2. sync.Mutex
  3. n int}
  4. hits.Lock()
  5. hits.n++
  6. hits.Unlock()

三、案例

手机拥有屏幕、电池、指纹识别等信息,将这些信息填充为 JSON 格式的数据。如果需要选择性地分离 JSON 中的数据则较为麻烦。Golang中的匿名结构体可以方便地完成这个操作。
首先给出完整的代码,然后再讲解每个部分。

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. )
  6. //定义手机屏幕
  7. type Screen01 struct {
  8. Size float64 //屏幕尺寸
  9. ResX, ResY int //屏幕分辨率 水平 垂直
  10. }
  11. //定义电池容量
  12. type Battery struct {
  13. Capacity string
  14. }
  15. //返回json数据
  16. func getJsonData() []byte {
  17. //tempData 接收匿名结构体(匿名结构体使得数据的结构更加灵活)
  18. tempData := struct {
  19. Screen01
  20. Battery
  21. HashTouchId bool // 是否有指纹识别
  22. }{
  23. Screen01: Screen01{Size: 12, ResX: 36, ResY: 36},
  24. Battery: Battery{"6000毫安"},
  25. HashTouchId: true,
  26. }
  27. jsonData, _ := json.Marshal(tempData) //将数据转换为json
  28. return jsonData
  29. }
  30. func main() {
  31. jsonData := getJsonData() //获取json数据
  32. fmt.Println(jsonData)
  33. fmt.Println("=========解析(分离)出的数据是===========")
  34. //自定义匿名结构体,解析(分离)全部数据
  35. allData := struct {
  36. Screen01
  37. Battery
  38. HashTouchId bool
  39. }{}
  40. json.Unmarshal(jsonData, &allData)
  41. fmt.Println("解析(分离)全部结构为:", allData)
  42. //自定义匿名结构体,通过json数据,解析(分离)对应的结构(可以是部分结构)
  43. screenBattery := struct {
  44. Screen01
  45. Battery
  46. }{}
  47. json.Unmarshal(jsonData, &screenBattery) //注意:此处只能为结构体指针(一般参数为interface{},都采用地址引用(即地址传递))
  48. fmt.Println("解析(分离)部分结构:", screenBattery)
  49. //自定义匿名结构体,解析(分离)部分结构
  50. batteryTouch := struct {
  51. Battery
  52. isTouch bool
  53. }{}
  54. json.Unmarshal(jsonData, &batteryTouch)
  55. fmt.Println("解析(分离)部分结构:", batteryTouch)
  56. //自定义匿名结构体,解析(分离)部分不存在的结构
  57. temp1 := struct {
  58. Battery
  59. Detail struct {
  60. Name string
  61. Price uint16
  62. }
  63. }{}
  64. json.Unmarshal(jsonData, &temp1)
  65. fmt.Println("解析(分离)部分不存在的结构", temp1)
  66. //自定义匿名结构体,解析(分离)完全不存在的结构
  67. temp2 := struct {
  68. User string
  69. Price uint16
  70. }{}
  71. json.Unmarshal(jsonData, &temp2)
  72. fmt.Println("解析(分离)完全不存在的结构:", temp2)
  73. }

image.png

注:匿名结构体可以组合不同类型的数据,使得处理数据变得更为灵活。尤其是在一些需要将多个变量、类型数据组合应用的场景,匿名结构体是一个不错的选择。

  1. json.Unmarshal(data []byte, v interface{})

//注意:参数 v 只能为结构体指针(一般参数为interface{},都采用地址引用(即地址传递))

原文 https://blog.csdn.net/weixin_42117918/article/details/90448756