英文:
How to declare the Type of a variable dynamically in GO, using if-else-like conditions?
问题
给定两种类型:
type A struct {
ID string
Content []int
}
和
type B struct {
ID string
Content map[string][]int
}
我需要一个函数根据条件告诉我以后要使用哪种类型(目的是正确地解析一个 JSON 字符串)。我想要一个像这样的函数:
func assign_typed_data(header string) interface{} {
switch header {
case "A":
d := new(A)
fmt.Printf("inner type is %T \n", *d) // inner type is A
return *d
case "B":
d := new(B)
fmt.Printf("inner type is %T \n", *d) // inner type is B
return *d
default:
}
}
在外部代码中,我可以调用它并像下面这样解析 JSON,但返回的值变成了 "map[string]interface{}"。
header := "A"
data := assign_typed_data(header)
fmt.Printf("outer type is %T \n", data) // outer type is map[string]interface{}
json.Unmarshal(json_data, &data)
我还尝试了直接在外部代码中使用简单的 if-else 语句,而不调用函数,像下面这样,但也失败了,因为定义的作用域是局部的。
if header == "A" {
data := *new(A)
} else if header == "B" {
data := *new(B)
}
json.Unmarshal(json_data, &data)
有没有可能在 Go 中实现这个目标?
英文:
Given two types
type A struct {
ID string
Content []int
}
and
type B struct {
ID string
Content map[string][]int
}
and I need a function to tell me which type to use hereafter according to conditions (the purpose is to unmarshal a json string properly). I want a function like
func assign_typed_data(header string) interface{} {
switch header {
case "A" :
d := new(A)
fmt.Printf('inner type is %T \n', *d) // inner type is A
return *d
case "B" :
d := new(B)
fmt.Printf('inner type is %T \n', *d) // inner type is B
return *d
default:
}
}
and in the outer code I can call it and unmarshal the json like follows, but the returned value turns to "map[string]interface{}".
header := "A"
data := assign_typed_data(header)
fmt.Printf('outter type is %T \n', data) // outter type is map[string]interface{}
json.Unmarshal(json_data, &data)
I also tried simple if-else statements in the outter code directly without calling a function, like follows, but failed as well because of defined scope is local.
if header == "A" {
data := *new(A)
}else if header == "B" {
data := *new(B)
}
json.Unmarshal(json_data, &data)
Is there a possible way to achieve this goal in GO?
答案1
得分: 3
你需要将期望的数据类型的指针传递给json.Unmarshal()
函数。也就是说,传递*A
或*B
。
然而,assign_typed_data()
函数返回的是interface{}
类型,而你取得了它的地址,所以你将传递*interface{}
。
将assign_typed_data()
函数修改为返回指针值*A
或*B
,并将data
直接传递给json.Unmarshal()
,因为它已经保存了指针值:
func createValue(header string) interface{} {
switch header {
case "A":
d := new(A)
fmt.Printf("inner type is %T \n", d) // inner type is *A
return d
case "B":
d := new(B)
fmt.Printf("inner type is %T \n", d) // inner type is *B
return d
default:
return nil
}
}
Testing it:
s := `{"ID":"abc","Content":[1,2,3]}`
data := createValue("A")
if err := json.Unmarshal([]byte(s), data); err != nil {
panic(err)
}
fmt.Printf("outer type is %T \n", data)
fmt.Printf("outer value is %+v \n", data)
s = `{"ID":"abc","Content":{"one":[1,2], "two":[3,4]}}`
data = createValue("B")
if err := json.Unmarshal([]byte(s), data); err != nil {
panic(err)
}
fmt.Printf("outer type is %T \n", data)
fmt.Printf("outer value is %+v \n", data)
输出结果为:
inner type is *main.A
outer type is *main.A
outer value is &{ID:abc Content:[1 2 3]}
inner type is *main.B
outer type is *main.B
outer value is &{ID:abc Content:map[one:[1 2] two:[3 4]]}
请查看相关的/可能重复的问题,以进一步了解该问题:
英文:
You have to pass a pointer to the expected data type to json.Unmarshal()
. That is, *A
or *B
.
Yet, assign_typed_data()
returns interface{}
and you take its address, so you'll be passing *interface{}
.
Change assign_typed_data()
to return the pointer value *A
or *B
, and pass data
as-is to json.Unmarshal()
as it will already hold a pointer value:
func createValue(header string) interface{} {
switch header {
case "A":
d := new(A)
fmt.Printf("inner type is %T \n", d) // inner type is *A
return d
case "B":
d := new(B)
fmt.Printf("inner type is %T \n", d) // inner type is *B
return d
default:
return nil
}
}
Testing it:
s := `{"ID":"abc","Content":[1,2,3]}`
data := createValue("A")
if err := json.Unmarshal([]byte(s), data); err != nil {
panic(err)
}
fmt.Printf("outer type is %T \n", data)
fmt.Printf("outer value is %+v \n", data)
s = `{"ID":"abc","Content":{"one":[1,2], "two":[3,4]}}`
data = createValue("B")
if err := json.Unmarshal([]byte(s), data); err != nil {
panic(err)
}
fmt.Printf("outer type is %T \n", data)
fmt.Printf("outer value is %+v \n", data)
Which outputs (try it on the Go Playground):
inner type is *main.A
outer type is *main.A
outer value is &{ID:abc Content:[1 2 3]}
inner type is *main.B
outer type is *main.B
outer value is &{ID:abc Content:map[one:[1 2] two:[3 4]]}
Please check related / possible duplicates which detail the issue further:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论