问题描述
我对 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"}}