The JSON-string in question looks like this:
{
"development":{
"connector":[
{"id":"connector-server-1", "host":"127.0.0.1", "port":4050, "wsPort":3050},
{"id":"connector-server-2", "host":"127.0.0.1", "port":4051, "wsPort":3051},
{"id":"connector-server-3", "host":"127.0.0.1", "port":4052, "wsPort":3052}
],
"chat":[
{"id":"chat-server-1", "host":"127.0.0.1", "port":6050},
{"id":"chat-server-2", "host":"127.0.0.1", "port":6051},
{"id":"chat-server-3", "host":"127.0.0.1", "port":6052}
],
"gate":[
{"id": "gate-server-1", "host": "127.0.0.1", "wsPort": 3014}
]
},
"production":{
"connector":[
{"id":"connector-server-1", "host":"127.0.0.1", "port":4050, "wsPort":3050},
{"id":"connector-server-2", "host":"127.0.0.1", "port":4051, "wsPort":3051},
{"id":"connector-server-3", "host":"127.0.0.1", "port":4052, "wsPort":3052}
],
"chat":[
{"id":"chat-server-1", "host":"127.0.0.1", "port":6050},
{"id":"chat-server-2", "host":"127.0.0.1", "port":6051},
{"id":"chat-server-3", "host":"127.0.0.1", "port":6052}
],
"gate":[
{"id": "gate-server-1", "host": "127.0.0.1", "wsPort": 3014}
]
}
}
and I want to parse it with code like this:
package config
import(
"sync"
"io/ioutil"
"encoding/json"
"errors"
"log"
)
type Service struct {
Id string `json:"id"`
Host string `json:"host"`
Port uint `json:"port"`
QueryPort uint `json:"queryPort"`
WsPort uint `json:"wsPort"`
ServiceType string
}
type Config struct {
Services []Service
Master Service
Mutex sync.RWMutex
}
func LoadServers(filepath, env string) (*Config, error) {
// 读取文件
content, err := ioutil.ReadFile(filepath)
if err != nil {
return nil, err
}
configs := make(map[string]map[string][]Service, 0)
err = json.Unmarshal(content, configs)
if err != nil {
return nil, err
}
}
I expect my code to parse this JSON-string to a map[string]map[string][]Service
.
but It shows the error:
json: Unmarshal(non-pointer map[string]map[string][]config.Service)
To build on @peterSO's answer, if you are up for something fancy, the encoding/json
package has the Decoder
type, which allows you to decode JSON directly from an io.Reader
, which is an interface that os.File
satisfies.
This would allow you to use the os
package, rather than io/ioutil
, which could save you an import (seeing as ioutil
already imports os
.)
package main
import (
"fmt"
"encoding/json"
"os"
)
func main() {
pathToFile := "jsondata.txt"
file, err := os.OpenFile(pathToFile, os.O_RDONLY, 0644)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
configs := make(map[string]map[string][]Service, 0)
err = json.NewDecoder(file).Decode(&configs)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
This way, you can decode JSON directly from a file or data stream. It's probably unnecessary if you're doing something simple and want to avoid this sort of thing, but nonetheless something to be aware of.
Good luck!
Pass the address of configs
to json.Unmarshal
. For example,
configs := make(map[string]map[string][]Service, 0)
err = json.Unmarshal(content, &configs)
if err != nil {
return nil, err
}
fmt.Println(configs)
Output:
map[production:map[connector:[{connector-server-1 127.0.0.1 4050 0 3050 } {connector-server-2 127.0.0.1 4051 0 3051 } {connector-server-3 127.0.0.1 4052 0 3052 }] gate:[{gate-server-1 127.0.0.1 0 0 3014 }] chat:[{chat-server-1 127.0.0.1 6050 0 0 } {chat-server-2 127.0.0.1 6051 0 0 } {chat-server-3 127.0.0.1 6052 0 0 }]] development:map[chat:[{chat-server-1 127.0.0.1 6050 0 0 } {chat-server-2 127.0.0.1 6051 0 0 } {chat-server-3 127.0.0.1 6052 0 0 }] gate:[{gate-server-1 127.0.0.1 0 0 3014 }] connector:[{connector-server-1 127.0.0.1 4050 0 3050 } {connector-server-2 127.0.0.1 4051 0 3051 } {connector-server-3 127.0.0.1 4052 0 3052 }]]]
&{[] { 0 0 0 } {{0 0} 0 0 0 0}}