Jestem stosunkowo nowy do Golang i mam problemy z ścisłym systemem pisania (jestem znacznie bardziej przyzwyczajony do słabo wpisanych języków).

Próbując napisać umiejętność ALEXA SMARTHOME, muszę stworzyć zdefiniowane struktury JSON (np.) W https://developer.amazon.com/en-US/docs/alexa/device-apis/alexa-contactsensor.html

Reakcja Uczerpek jest tam, gdzie zaczynam mieć kłopoty, w szczególności z kontekstem.

Przykład wygląda jak:

  "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"
        },
        "timeOfSample": "2017-02-03T16:20:50.52Z",
        "uncertaintyInMilliseconds": 0
      }
    ]
  }

Na pierwszy rzut oka wygląda na to wystarczająco proste:

    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"`

Ale pole "Wartość" jest tam, gdzie mam problem.

W pierwszym elemencie tablicy mamy prosty ciąg

        "value": "NOT_DETECTED",

Ale element drugi jest strukturą

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

(To nie wydaje się być literami w dokumentach; jest powtarzany w https://developer.amazon.com/en-us/docs/alexa/device-apis/alexa-endpointhealth.html i gdzie indziej oraz inne).

I to jest miejsce, w którym ścisły pisanie Golang i wiedzy o języku zaczyna mnie pokonać.

Jak mogę modelować ten value element, ponieważ nie wydaje się mieć stałego typu?

Czy jest na to lepszy sposób?

-2
Stephen Harris 19 kwiecień 2021, 05:57

2 odpowiedzi

Najlepsza odpowiedź

Korzystanie z podpowiedzi z MkPriva myślę, że wymyśliłem prosty dowód koncepcji rozwiązania przy użyciu interface{} i anonimowych struktur

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))
}

Uruchamianie daje dwa wyjścia:

{"value":"version1"}
{"value":{"value":"version2"}}
-1
Stephen Harris 19 kwiecień 2021, 03:14

Utwórz taki typ:

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)
}

I użyj go w strukturze:

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

Gdy wartość jest "OK" Your Value.Valid będzie true, inaczej sprawdzić Value.Error dla wartości analizowanej.

0
derkan 19 kwiecień 2021, 14:54