面试题答案
一键面试- 定义结构体:首先定义一个结构体,用于存储配置文件中的数据。结构体的字段标签用于映射JSON中的键。
type Config struct {
ServerAddr string `json:"server_addr"`
Database struct {
Host string `json:"host"`
Port int `json:"port"`
Username string `json:"username"`
Password string `json:"password"`
} `json:"database"`
}
- 读取JSON文件:使用
os.Open
函数打开JSON文件,并使用json.NewDecoder
进行解码。
file, err := os.Open("config.json")
if err != nil {
log.Fatalf("Failed to open config file: %v", err)
}
defer file.Close()
var config Config
decoder := json.NewDecoder(file)
if err := decoder.Decode(&config); err != nil {
log.Fatalf("Failed to decode config file: %v", err)
}
- 使用反射动态加载:如果要使用反射动态加载数据到结构体,可以按照以下步骤:
- 获取结构体的反射值对象。
- 遍历结构体字段,根据字段标签在JSON数据中查找对应的值并设置。
func loadConfigWithReflection(data []byte, target interface{}) error {
var jsonMap map[string]interface{}
if err := json.Unmarshal(data, &jsonMap); err != nil {
return err
}
valueOf := reflect.ValueOf(target).Elem()
for i := 0; i < valueOf.NumField(); i++ {
field := valueOf.Field(i)
tag := valueOf.Type().Field(i).Tag.Get("json")
if tag != "" {
if val, exists := jsonMap[tag]; exists {
setValue(field, reflect.ValueOf(val))
}
}
}
return nil
}
func setValue(field reflect.Value, value reflect.Value) {
if field.Type().Kind() == reflect.Struct {
for i := 0; i < field.NumField(); i++ {
subTag := field.Type().Field(i).Tag.Get("json")
if subTag != "" {
if subVal, exists := value.MapIndex(reflect.ValueOf(subTag)); exists {
setValue(field.Field(i), subVal)
}
}
}
} else {
if field.Type().ConvertibleTo(value.Type()) {
field.Set(value.Convert(field.Type()))
}
}
}
- 调用动态加载函数:
data, err := ioutil.ReadFile("config.json")
if err != nil {
log.Fatalf("Failed to read config file: %v", err)
}
var config Config
if err := loadConfigWithReflection(data, &config); err != nil {
log.Fatalf("Failed to load config: %v", err)
}
这样就可以通过反射动态加载JSON配置文件中的数据到结构体。但在实际应用中,直接使用json.Unmarshal
解码到结构体更为常用和简洁。反射方式通常用于需要更动态、灵活的配置加载场景。