微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何定义具有不同字段类型的 GoLang 结构

如何解决如何定义具有不同字段类型的 GoLang 结构

我对 GoLang 比较陌生,并且在使用严格类型系统时遇到问题(我更习惯于弱类型语言)。

在尝试编写 Alexa SmartHome 技能时,我需要创建(例如)在 https://developer.amazon.com/en-US/docs/alexa/device-apis/alexa-contactsensor.html 处定义的 JSON 结构

StateReport Response 是我开始遇到问题的地方,尤其是上下文。

示例如下:

  "context": {
    "properties": [
      {
        "namespace": "Alexa.ContactSensor","name": "detectionState","value": "NOT_DETECTED","timeOfSample": "2017-02-03T16:20:50.52Z","uncertaintyInMilliseconds": 0
      },{
        "namespace": "Alexa.EndpointHealth","name": "connectivity","value": {
          "value": "OK"
        },"uncertaintyInMilliseconds": 0
      }
    ]
  }

乍一看,这看起来很简单:

    Context struct {
        Properties []struct {
            Namespace                 string    `json:"namespace"`
            Name                      string    `json:"name"`
            Value                     string    `json:"value"`
            Timeofsample              time.Time `json:"timeOfSample"`
            Uncertaintyinmilliseconds int       `json:"uncertaintyInMilliseconds"`
        } `json:"properties"`
    } `json:"context"`

但是“值”字段是我遇到问题的地方。

在数组的第一个元素中,我们有一个简单的字符串

        "value": "NOT_DETECTED",

但是第二个元素是一个结构

        "value": {
          "value": "OK"
        },

(这似乎不是文档中的错字;它在 https://developer.amazon.com/en-US/docs/alexa/device-apis/alexa-endpointhealth.html 和其他地方也有重复)。

这就是 GoLang 的严格类型和我的语言知识开始打败我的地方。

我如何建模这个 value 元素,因为它似乎没有固定类型?

或者有更好的方法吗?

解决方法

创建一个这样的类型:

import (
    "bytes"
    "encoding/json"
    "fmt"
)

// nullOK is a JSON OK literal
var nullOK = []byte("OK")

type ValueString struct {
    Error string
    Valid bool
}

// UnmarshalJSON implements json.Unmarshaler.
func (s *ValueString) UnmarshalJSON(data []byte) error {
    if bytes.Equal(data,nullOK) {
        s.Valid = true
        return nil
    }

    if err := json.Unmarshal(data,&s.Error); err != nil {
        return fmt.Errorf("checking OK: couldn't unmarshal JSON: %w",err)
    }

    s.Valid = false
    return nil
}

// MarshalJSON implements json.Marshaler.
func (s ValueString) MarshalJSON() ([]byte,error) {
    if s.Valid {
        return []byte("OK"),nil
    }
    return json.Marshal(s.Error)
}

并在您的结构中使用它:

...
Value                     ValueString    `json:"value"`
...

当值为“OK”时,您的 Value.Valid 将为 true,否则检查 Value.Error 以获取解析值。

,

使用 mkopriva 的提示,我想我想出了使用 interface{} 和匿名结构的简单概念验证解决方案

package main

import "encoding/json"
import "fmt"

type Foo struct {
        Value interface{} `json:"value"`
}

func main() {
        v1 := Foo{Value: "version1"}
        j1,_ := json.Marshal(v1)
        fmt.Println(string(j1))

        v2 := Foo{Value: struct {
                Value string `json:"value"`
        }{Value: "version2"}}
        j2,_ := json.Marshal(v2)
        fmt.Println(string(j2))
}

运行这个会得到两个输出:

{"value":"version1"}
{"value":{"value":"version2"}}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。