Golang匿名结构体的使用场景


结构体基础
结构体 (struct)  多个不同类型的字段 组成一种复合类型 按声明时的字段顺序初始化
    type user struct {
        name string
        age byte
    }    
    user := user{"Tom", 2}   
定义匿名结构体 没有 type 关键字 与其他定义类型的变量一样
在函数外部 需在结构体变量前加上 var 关键字
在函数内部 可省略 var 关键字
// 在函数外部定义匿名结构体并赋值给
var config struct {
    APIKey string
    OAuthConfig oauth.Config
}
datadata := struct {// 定义并初始化并赋值
    Title string
    Users []*User
}{title,users}
匿名结构体使用场景

组织全局变量

属于同一类的全局变量可通过匿名结构体组织在一起
var config struct {
        APIKey      string
        OAuthConfig oauth.Config
}    
config.APIKey = "BADC0C0A"

数据模版

后端把 数据组织成 前端需要的格式传给渲染模版
package main
    import (
    "html/template"
    "net/http"
    "strings"
    )
    type Paste struct {
    Expiration string
    Content    []byte
    UUID       string
    }
    func pasteHandler(w http.ResponseWriter, r *http.Request) {
    paste_id := strings.TrimPrefix(r.URL.Path, "/paste")
    paste := &Paste{UUID: paste_id}
    keep_alive := false
    burn_after_reading := false
    data := struct {
            Paste *Paste
            KeepAlive bool
            BurnAfterReading bool
    } {paste,keep_alive,burn_after_reading,    }
    t, _ := template.ParseFiles("templates/paste.html")
    t.Execute(w, data)
}
匿名函授定义并初始化之后赋值给 data 变量  除了把 Paste 结构体对象的值传给前端之外 还额外添加了必要的字段
前端需要后端返回 标志变量 作为判断条件是否显示某一块内容
Expiration: {{ .Paste.Expiration }}
UUID: {{ .Paste.UUID}}
{{ if .BurnAfterReading }}
BurnAfterReading: True{{ else }}
BurnAfterReading: False{{ end }}

测试案例数据

测试代码 常用到匿名结构体生成用例的输入输出
为了覆盖 测试维度 常结合切片 构成测试样例 尽可能 覆盖所有可能发生情况
var indexRuneTests = []struct {
        s    string
        rune rune    out  int}{
        {"a A x", 'A', 2},
        {"some_text=some_value", '=', 9},
        {"a", 'a', 3},
        {"ab", '', 4},
}

嵌入式锁

(Embedded lock)
    var hits struct {
            sync.Mutex
            n int}
    hits.Lock()
    hits.n++
    hits.Unlock()
案例 手机有屏幕 电池 指纹识别等信息
将这些信息填充为 JSON 格式的数据
如果需要选择性地分离 JSON 中的数据则较为麻烦
Go 匿名结构体 方便地完成这个操作
    package main    
    import (
        "encoding/json"
        "fmt"
    )    
    type Screen01 struct {//定义手机屏幕
        Size       float64 //屏幕尺寸
        ResX, ResY int //屏幕分辨率 水平 垂直
    }    
    type Battery struct {//定义电池容量
        Capacity string
    }    
    func getJsonData() []byte {//返回json数据        
        tempData := struct {//tempData 接收匿名结构体(匿名结构体使 数据的结构 灵活)
            Screen01
            Battery
            HashTouchId bool  // 是否有指纹识别
        }{
            Screen01:    Screen01{Size: 12, ResX: 36, ResY: 36},
            Battery:     Battery{"6000毫安"},
            HashTouchId: true,
        }
        jsonData, _ := json.Marshal(tempData) //将数据转换为json
        return jsonData
    }
    func main() {
        jsonData := getJsonData() //获取json数据
        fmt.Println(jsonData)
        fmt.Println("=解析 分离 出的数据是=")        
        allData := struct {//自定义匿名结构体 解析(分离)全部数据
            Screen01
            Battery
            HashTouchId bool
        }{}
        json.Unmarshal(jsonData, &allData)
        fmt.Println("解析(分离)全部结构为:", allData)        
        
        screenBattery := struct {//自定义匿名结构体 通过json数据 解析分离对应的结构(可以是部分结构)
            Screen01
            Battery
        }{}
        json.Unmarshal(jsonData, &screenBattery) //注意:此处只能为结构体指针(一般参数为interface{} 都采用地址引用(即地址传递))
        fmt.Println("解析(分离)部分结构:", screenBattery)

        batteryTouch := struct {    //自定义匿名结构体 解析 分离 部分结构
            Battery
            isTouch bool
        }{}
        json.Unmarshal(jsonData, &batteryTouch)
        fmt.Println("解析(分离)部分结构:", batteryTouch)       
        temp1 := struct {//自定义匿名结构体 解析 分离 部分不存在的结构
            Battery
            Detail struct {
                Name  string
                Price uint16
            }
        }{}
        json.Unmarshal(jsonData, &temp1)
        fmt.Println("解析(分离)部分不存在的结构", temp1)
                
        temp2 := struct {//自定义匿名结构体 解析(分离)完全不存在的结构
            User  string
            Price uint16
        }{}
        json.Unmarshal(jsonData, &temp2)
        fmt.Println("解析(分离)完全不存在的结构:", temp2)
    }
匿名结构体 组合不同类型的数据  处理数据更灵活
在需要将多个变量 类型数据组合应用的场景 匿名结构体是一个不错的选择
json.Unmarshal(data []byte, v interface{})
参数 v 只能为结构体指针(一般参数为interface{} 都采用地址引用(即地址传递))

定义数据结构

首先 定义手机的各种数据结构体 如屏幕和电池    
    type Screen struct {// 定义手机屏幕
    Size float32 // 屏幕尺寸
    ResX, ResY int // 屏幕水平和垂直分辨率
    }    
    type Battery struct {// 定义电池
      Capacity int // 容量
    }
定义了屏幕结构体和电池结构体 分别描述屏幕和电池的各种细节参数
准备手机数据结构 填充数据 将数据序列化为 JSON 格式的字节数组
func genJsonData() []byte {// 生成JSON数据    
    raw := &struct {// 完整数据结构
    Screen
    Battery
    HasTouchID bool // 序列化时添加的字段:是否有指纹识别
    }{Screen: Screen{    Size: 5.5,ResX: 1920,ResY: 1080,},
            Battery: Battery{    2910,    },    
        HasTouchID: true,// 是否有指纹识别
    }
    jsonData, _ := json.Marshal(raw)    // 将数据序列化为JSON
    return jsonData
}

分离JSON数据

调用 genJsonData 获得 JSON 数据 将需要的字段填充到匿名结构体实例中 通过 json.Unmarshal 反序列化 JSON 数据达成分离 JSON 数据效果
    func main() {
    jsonData := genJsonData()    // 生成一段JSON数据
    fmt.Println(string(jsonData))// 只需要屏幕和指纹识别信息的结构和实例
    screenAndTouch := struct {
    Screen
    HasTouchID bool
    }{}
    // 反序列化到screenAndTouch中
    json.Unmarshal(jsonData, &screenAndTouch)
    // 输出screenAndTouch的详细结构
    fmt.Printf("%+v\n", screenAndTouch)
    // 只需要电池和指纹识别信息的结构和实例
    batteryAndTouch := struct {
    Battery
    HasTouchID bool
    }{}
    // 反序列化到batteryAndTouch
    json.Unmarshal(jsonData, &batteryAndTouch)
    // 输出screenAndTouch的详细结构
    fmt.Printf("%+v\n", batteryAndTouch)
    }