Golang中如何访问map[string]interface{}变量的子键值
Golang中如何访问map[string]interface{}变量的子键值
var x_inboundbody map[string]interface{}
_ = json.Unmarshal(Inboundbody, &x_inboundbody)
我有一个深度为3到4层的结构,类似于JSON结构(由于其动态特性,无法预先创建结构体),并且每条记录的结构都是动态变化的。
我知道在我的结构中,从根级别开始存在以下键:entities.overalScore.overallScore,我希望能访问到它。
我想提取如下所示的数值60。
有人能帮忙吗?

更多关于Golang中如何访问map[string]interface{}变量的子键值的实战教程也可以访问 https://www.itying.com/category-94-b0.html
我确实是……因为我正在将其保存到文件中。
G
更多关于Golang中如何访问map[string]interface{}变量的子键值的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
请检查你是否确实从你的HTTP调用中接收到了数据。
// 代码部分保持原样,不翻译
检查解析后的响应是否为空或存在? 或者只是先部分解析响应,以区分不同的响应?
…解决方案根据此处的建议编译…并通过向ChatGPT提出想法并进一步引导这些问题…
有趣 ;)
G
我也使用 Python,那边要简单得多 😉
目前这部分工作要转向 Python 还为时过早。
但也许将来某个时候会这么做。
G
也许在 https://goplay.tools/ 上为你的问题制作一个小的可运行的概念验证会更容易?你可以把有问题的 JSON 粘贴在那里,这样我们就可以一起尝试解析它了。
如原帖所述,
我无法为此定义一个结构体,因为响应过于动态。 我只展示了一个响应,但我有15个。它们都来自同一个调用,只有在我获取到并将其放入一个可引用的对象后,我才能弄清楚它是哪个有效载荷。
G
因此,我成功编译了一个超集结构体,它应该/将会涵盖各种消息/响应。
既然我已经让上面那个方法正常工作了,
接下来我将按照上面的方式(以及下面 @Dean_Davidson 的例子),通过类型转换到结构体来创建第二个方法。

G
比较 map[string]interface{} 与 struct 这两种 JSON API 方式是一个很好的练习。
但我认为,最终这完全取决于你对响应中变化的确切了解程度,这样你才能找到最佳位置来处理错误或决定消息其余部分的内容。
我理解这种挫败感,但我不太确定最终在 Python 或其他语言中这是否会更容易?困难的部分始终是错误处理。
如果我的数据结构更简单一些,我大概能想象出这如何运作。
如果有一个简单的函数,接收一个字节并返回一个可寻址的 JSON 对象,那就太好了,这样就可以像 a := jsonObjName["attribute"]["subAttribute"] 这样引用它。
我尤其这么想,因为这门语言是围绕 API 创建的,有时传入的结构可能并非 100% 已知,但已知某些属性总是存在的。
json.RawMessage 在这里可能是你的好帮手。看看这个例子,他们最初并不知道子类型会是什么:
json package - encoding/json - Go Packages
Package json implements encoding and decoding of JSON as defined in RFC 7159.
稍微修改了我的 for 循环,采纳了建议的浮点数类型转换。
for _, value := range overallScores {
if value != nil {
f, ok := value.(float64) // 因为有 ok 值,所以这里不会 panic
if ok {
if f > float64(vScore) {
vScore = f
}
}
}
}
或者
for _, value := range overallScores {
if value != nil {
f, ok := value.(float64) // 因为有 ok 值,所以这里不会 panic
if ok && f > float64(vScore){
vScore = f
}
}
}
我简化了JSON,以便更容易满足你的基本要求。 运行示例: https://goplay.tools/snippet/RIjLk-G-2u8
提到的那个网站确实对生成结构体非常有帮助,但在这种情况下,我也可以清理结构体标签(json: ...),因为变量已经有了正确的名称。
func main() {
type Rsp struct {
ResponseBody struct {
Entities []struct {
OverallScore struct {
OverallScore int
}
}
}
}
var rsp Rsp
json.Unmarshal([]byte(rawJsonString), &rsp)
for _, v := range rsp.ResponseBody.Entities {
fmt.Println(v.OverallScore.OverallScore)
}
}
我不会建议你转向Python。我无法忍受它没有编译器来捕获错误。在我看来,编译器是最重要的重构工具。
但我相当确定你在Go中还没有达到最优形式。
首先,如果不检查ok就将interface{}转换为float,存在引发panic的风险。(你没有对vScore这样做。)
这段代码演示了你可以不使用ok进行转换,但如果转换失败,它会产生panic:
var i1 interface{} = 3.14
fmt.Println(i1)
f1, ok := i1.(float64)
fmt.Println(ok)
fmt.Println(f1)
var i2 interface{} = "not a float"
fmt.Println(i2)
//var f2 float64
f2, ok := i2.(float64) // this won't panic because there's an ok
fmt.Println(ok)
fmt.Println(f2)
f3 := i2.(float64) // this can panic
fmt.Println(f3)
我也刚刚了解到,当存在ok时,它不会引发panic。这很有趣。
解决方案虽然粗糙,但有效…
InboundRequest, _ := http.NewRequest("POST", vGeneral.Httpposturl, bytes.NewBuffer(InboundBytes))
InboundRequest.Header.Set("Content-Type", "application/json; charset=UTF-8")
InboundResponse, _ := client.Do(InboundRequest)
defer InboundResponse.Body.Close()
jsonDataOutboundResponsebody, _ = io.ReadAll(InboundResponse.Body)
var outboundbodyMap map[string]interface{}
_ = json.Unmarshal(jsonDataOutboundResponsebody, &outboundbodyMap)
// 访问嵌套数组
entities, ok := inboundbodyMap["entities"].([]interface{})
if !ok {
fmt.Println("Error accessing entities")
return
}
var vScore float64
vScore = 0.0
for _, entity := range entities {
overallScoreMap, ok := entity.(map[string]interface{})
if !ok {
fmt.Println("Error accessing entity details")
return
}
// 访问每种语言的详细信息映射
overallScores, ok := overallScoreMap["overallScore"].(map[string]interface{})
if !ok {
fmt.Println("Error accessing language details")
return
}
for _, value := range overallScores {
if value != nil {
if value.(float64) > float64(vScore) {
vScore = value.(float64)
}
}
}
}
fmt.Println(vScore)
最简单的方法是将你的JSON映射到一个Go结构体(使用JSON-to-Go: 即时将JSON转换为Go)。
否则,你必须注意,从map中获取的每个元素都是一个struct{},因此必须将其转换为适当的数据类型。代码可能类似于:
Inboundbody := []byte(json_string)
var x_inboundbody map[string]interface{}
_ = json.Unmarshal(Inboundbody, &x_inboundbody)
fmt.Println(x_inboundbody) // map[string]interface{}
responseBodyInterface := x_inboundbody["responseBody"] // interface{}
responseBodyMap := responseBodyInterface.(map[string]interface{}) // map[string]interface{}
fmt.Printf("responseBodyMap :%T\n%v\n", responseBodyMap, responseBodyMap)
entitiesInterface := responseBodyMap["entities"] // interface{}
entitiesSlice := entitiesInterface.([]interface{}) // []interface{}
entitiesMap := entitiesSlice[0].(map[string]interface{}) // map[string]interface{}
fmt.Printf("entitiesMap :%T\n%v\n", entitiesMap, entitiesMap)
overallScoreInterface := entitiesMap["overallScore"] // // interface{}
overallScoreMap := overallScoreInterface.(map[string]interface{})
fmt.Printf("overallScoreMap :%T\n%+v\n", overallScoreMap, overallScoreMap)
overallScore := overallScoreMap["overallScore"]
fmt.Printf("overallScore :%T\n%v\n", overallScore, overallScore)
请查看下面的错误信息……同时我也添加了 <code> 来显示 inboundBody 的来源。
InboundRequest, _ := http.NewRequest("POST", vGeneral.Httpposturl, bytes.NewBuffer(InboundBytes))
InboundRequest.Header.Set("Content-Type", "application/json; charset=UTF-8")
InboundResponse, _ := client.Do(InboundRequest)
defer InboundResponse.Body.Close()
Inboundbody, _ = io.ReadAll(InboundResponse.Body)
//Inboundbody := []byte(json_string)
var x_inboundbody map[string]interface{}
_ = json.Unmarshal(Inboundbody, &x_inboundbody)
fmt.Println(x_inboundbody) // map[string]interface{}
responseBodyInterface := x_inboundbody["responseBody"] // interface{}
responseBodyMap := responseBodyInterface.(map[string]interface{}) // map[string]interface{}
fmt.Printf("responseBodyMap :%T\n%v\n", responseBodyMap, responseBodyMap)
Access-Control-Allow-Origin:[*] Cache-Control:[no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0] Connection:[keep-alive] Content-Length:[8044] Content-Type:[application/json] Date:[Thu, 05 Oct 2023 06:29:12 GMT] Server:[webserver] X-Content-Type-Options:[nosniff] X-Xss-Protection:[1; mode=block]]
2023/10/05 08:29:11 INFO: Inbound response Status : 200 OK
2023/10/05 08:29:11 INFO:
panic: interface conversion: interface {} is nil, not map[string]interface {}
goroutine 1 [running]:
main.runLoader({0x16d8bb33e?, 0x14000134a70?})
/Users/george/Desktop/ProjectsCommon/fs/fs_scenario_tester2.2/cmd/producer.go:1166 +0x771c
main.main()
/Users/george/Desktop/ProjectsCommon/fs/fs_scenario_tester2.2/cmd/producer.go:1688 +0x90
exit status 2
g-mbp.local:/Users/george/Desktop/ProjectsCommon/fs/fs_scenario_tester2.2 > ```
在Go中访问多层嵌套的map[string]interface{}时,需要进行类型断言和逐层访问。以下是访问entities.overalScore.overallScore的示例代码:
package main
import (
"encoding/json"
"fmt"
)
func main() {
// 示例JSON数据
jsonData := `{
"entities": {
"overalScore": {
"overallScore": 60
}
}
}`
var x_inboundbody map[string]interface{}
_ = json.Unmarshal([]byte(jsonData), &x_inboundbody)
// 逐层访问嵌套的map
if entities, ok := x_inboundbody["entities"].(map[string]interface{}); ok {
if overalScore, ok := entities["overalScore"].(map[string]interface{}); ok {
if overallScore, ok := overalScore["overallScore"].(float64); ok {
fmt.Printf("overallScore: %v\n", overallScore) // 输出: overallScore: 60
}
}
}
}
对于更通用的解决方案,可以创建一个辅助函数来处理动态深度的访问:
func getNestedValue(data map[string]interface{}, keys ...string) (interface{}, bool) {
var current interface{} = data
for _, key := range keys {
if m, ok := current.(map[string]interface{}); ok {
if val, exists := m[key]; exists {
current = val
} else {
return nil, false
}
} else {
return nil, false
}
}
return current, true
}
// 使用示例
func main() {
jsonData := `{
"entities": {
"overalScore": {
"overallScore": 60,
"details": {
"score": 85
}
}
}
}`
var x_inboundbody map[string]interface{}
_ = json.Unmarshal([]byte(jsonData), &x_inboundbody)
// 访问多层嵌套的值
if value, ok := getNestedValue(x_inboundbody, "entities", "overalScore", "overallScore"); ok {
if score, ok := value.(float64); ok {
fmt.Printf("Score: %v\n", score) // 输出: Score: 60
}
}
// 访问更深层的值
if value, ok := getNestedValue(x_inboundbody, "entities", "overalScore", "details", "score"); ok {
if score, ok := value.(float64); ok {
fmt.Printf("Detail Score: %v\n", score) // 输出: Detail Score: 85
}
}
}
如果JSON结构中有数组,需要额外处理:
func getNestedValueWithArrays(data interface{}, keys ...string) (interface{}, bool) {
current := data
for _, key := range keys {
switch v := current.(type) {
case map[string]interface{}:
if val, exists := v[key]; exists {
current = val
} else {
return nil, false
}
case []interface{}:
// 这里可以添加数组索引的处理逻辑
// 例如: 如果key是数字字符串,转换为索引
return nil, false
default:
return nil, false
}
}
return current, true
}
这些方法可以处理动态深度的JSON结构访问,通过类型断言确保类型安全。

