Загрузка пользовательских настроек в Go - PullRequest
0 голосов
/ 01 мая 2018

Я использую файлы JSON для хранения / загрузки моей конфигурации. Допустим, у меня есть следующее:

type X interface

// implements interface X
type Y struct {
    Value string
}

// implements interface X
type Z struct {
    Value string
}

type Config struct {
    interfaceInstance X `json:"X"`
}

Пример файла конфигурации:

{
  "config1": {
    "X": {
      "type": "Z",
      "Value": "value_1"
    }
  },


  "config2": {
    "X": {
      "type": "Y",
      "Value": "value_2"
    }
  }
}

Я хочу иметь возможность определять файлы конфигурации примерно так, как в этом примере, и иметь возможность динамически загружать JSON как struct Y или struct Z. Любые предложения о том, как это сделать? Я использую простой json.Decoder для загрузки JSON в виде структуры.

decoder := json.NewDecoder(file)
err = decoder.Decode(&config)

1 Ответ

0 голосов
/ 02 октября 2018

Одной из возможных стратегий было бы реализовать json.Unmarshaler для типа Config таким образом, чтобы вы сначала разархивировали общий объект и затем проверили атрибут type, включив строку типа, разархивировали тот же байт. Массив в известный тип и назначить член "interfaceInstance" конфигурации.

Например ( Go Playground ):

// Note the slightly different JSON here...
var jsonstr = `{
  "config1": {
    "type": "Z",
    "Value": "value_1"
  },
  "config2": {
    "type": "Y",
    "Value": "value_2"
  }
}`

func main() {
  config := map[string]Config{}
  err := json.Unmarshal([]byte(jsonstr), &config)
  if err != nil {
    panic(err)
  }

  fmt.Printf("OK: %#v\n", config)
  // OK: map[string]main.Config{
  //   "config1": main.Config{interfaceInstance:main.Z{Value:"value_1"}},
  //   "config2": main.Config{interfaceInstance:main.Y{Value:"value_2"}},
  // }
}

func (c *Config) UnmarshalJSON(bs []byte) error {
  // Unmarshal into an object to inspect the type.
  var obj map[string]interface{}
  err := json.Unmarshal(bs, &obj)
  if err != nil {
    return err
  }

  // Unmarshal again into the target type.
  configType := obj["type"].(string)
  switch configType {
  case "Y":
    var y Y
    if err = json.Unmarshal(bs, &y); err == nil {
      c.interfaceInstance = y
    }
  case "Z":
    var z Z
    if err = json.Unmarshal(bs, &z); err == nil {
      c.interfaceInstance = z
    }
  default:
    return fmt.Errorf("unexpected type %q", configType)
  }
  return err
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...