如何在golang中将接口中的字符串转换为[]string?

20

我正在解析一个包含字符串数组的JSON对象:

var ii interface{}
json := "{\"aString\": [\"aaa_111\", \"bbb_222\"], \"whatever\":\"ccc\"}"

err := json.Unmarshal([]byte(json), &ii)
if err != nil {
    log.Fatal(err)
}
data := ii.(map[string]interface{})
fmt.Println(data["aString"]) // outputs: ["aaa_111" "bbb_222"]

我试图将data["aString"]转换为[]string,以便能够循环遍历它,但是失败了:

 test := []string(data["aString"]).([]string)
 fmt.Println(test) // panic -> interface conversion: 
                   //          interface is string, not []string

我该如何转换data["aString"]


编辑:

我表达不清楚。如果我打印data,我有这样一个映射:

map[aString:["BBB-222","AAA-111"] whatever:ccc]

我想遍历aString(操作每个数组条目)。但我找不到方法,因为aString是type interface {}类型:

for i, v := range aString { // <-- fails
     // ...
     fmt.Println(i, v)
}

这就是为什么我想要转换aString。我不想将一个看起来像数组的字符串转换成数组。


1
你知道你的JSON的准确结构吗?(字段是否被定义明确或者可能会有变化) - T. Claverie
你的变量ii应该已经是一个map[string]interface {}了... 我看不出来为什么要进行类型断言data := ii.(map[string]interface {})。修复这个问题并不能解决你的问题,我只是注意到了它。 - Snowman
1
尝试使用以下代码:aStringValue := ii.(map[string]interface {})["aString"] - Snowman
4个回答

47

我建议您普遍远离这种实现方式。您的json可能会有所不同,但您可以轻松地使用对象并避免所有这些类型不安全的废话。

无论如何,那个转换不起作用,因为切片内部的类型不是string,它们还是interface{}。您必须迭代集合,然后对每个项目进行类型断言,如下所示:

aInterface := data["aString"].([]interface{})
aString := make([]string, len(aInterface))
for i, v := range aInterface {
    aString[i] = v.(string)
}

@jérôme,我和Evan的想法一致,但如果你真的需要将JSON数据解组为映射(这是有效的用例),请考虑使用mxj - kostix
1
@Jérôme 哦,好的。所以首先你必须在 interface{} 上使用 assert 转换为 []interface{},我可以编辑我的答案以反映这一点。 - evanmcdonnal
1
请将第二个 data["aString"] 更新为 aInterface。这样就可以正常工作了 :-) - MTarantini
1
@evanmcdonnal,代码写得很不错,但有一个小错误,你在将字符串追加到aString数组中,而该数组已经分配了正确的大小。只需赋值即可:aString[i] = v.(string) playground - Sylvain
@Sylvain 是的,同意。在规模上,小优化非常重要。使用更好的解决方案进行编辑。 - evanmcdonnal
显示剩余2条评论

5

这是您需要的吗?

package main

import (
    "fmt"
    "encoding/json"
)

func main() {
    js := "{\"aString\": [\"aaa_111\", \"bbb_222\"], \"whatever\":\"ccc\"}"
    a := make(map[string]interface{})
    json.Unmarshal([]byte(js), &a)
    for _, v := range a["aString"].([]interface{}) {
        str := v.(string)
        fmt.Println(str)
    }
}

请在Go Playground进行检查。


0

另一种方法是使用struct

package main

import (
   "encoding/json"
   "fmt"
)

func main() {
   s := []byte(`{"aString": ["aaa_111", "bbb_222"], "whatever":"ccc"}`)
   var t struct {
      Astring []string
      Whatever string
   }
   json.Unmarshal(s, &t)
   fmt.Printf("%+v\n", t) // {Astring:[aaa_111 bbb_222] Whatever:ccc}
}

0
我通过编组和解组来解决这个问题:
type Paragraph struct {
    Paragraph_id          string    `json:"paragraph_id"`
    Parent_document_id    string    `json:"parent_document_id"`
    Page_in_document      int       `json:"page_in_document"`
    Text                  string    `json:"text"`
    Previous_paragraph_id string    `json:"previous_paragraph_id"`
    Parent_paragraph_id   string    `json:"parent_paragraph_id"`
    Child_paragraph_ids   []string  `json:"child_paragraph_ids"`
    Next_paragraph_id     string    `json:"next_paragraph_id"`
    Summary               string    `json:"summary"`
    Vector                []float64 `json:"vector"`
    Definitions           []string  `json:"definitions"`
    Keywords              []string  `json:"keywords"`
    IsLeaf                bool      `json:"leaf"`
}

_, err := session.ExecuteRead(db_ctx, func(transaction neo4j.ManagedTransaction) (any, error) {
        result, _:= transaction.Run(db_ctx,
            "MATCH (paragraph:Paragraph) RETURN paragraph",
            map[string]any{},
        )

    paragraphs = []Paragraph{}

    for result.Next(db_ctx) {
            record := result.Record()       
            para, _ := record.Get("paragraph")
            properties := para.(neo4j.Node).GetProperties()
            bytes, _ := json.Marshal(properties)

            var paragraph knowledge_structs.Paragraph
            json.Unmarshal(bytes, &paragraph)

            paragraphs = append(paragraphs, paragraph)
}

不确定它有多高效 ;)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接