英文:
Typing in recursive golang function call
问题
我正在为Github上的一个名为jsonget的Go项目添加“数组通配符”。以下是我所说的数组通配符的示例:
> echo "[{product:'coffee', price:2.10}, {product:'beer', price:3.80}]" | jsonget '*.price'
[2.10, 3.80]
我的分支的代码在这里。
我遇到的问题是类型问题,当GetValue
遇到*
字符时,它会递归调用GetValue
来处理子表达式,但类型始终返回为字符串。
例如,在测试文件中,我给它这段json:
{
"inventory": [
{"name": "mountain bike", "price": 251.0},
{"name": "red wagon", "price": 90.10},
{"name": "kinesis advantage", "price": 300.0},
{"name": "a ticket to Mars", "price": 1200000000.0}
]
}
然后查询inventory[*].price
,期望得到[251,90.1,300,1.2e+09]
,但实际上得到的是["251","90.1","300","1.2e+09"]
。
我想避免在这里使用反射,但我没有看到其他的方法来解决这个问题。
英文:
I am working on adding 'array wildcards' to a Go project on Github called jsonget. Here's an example of what I mean by array wildcards:
> echo "[{product:'coffee', price:2.10}, {product:'beer', price:3.80}]" | jsonget '*.price'
[2.10, 3.80]
The code for my branch is here
The problem I am running into is with typing, when GetValue
encounters a *
character, it recurses, calling GetValue
on the subexpression, but the type always comes back as a string.
For example, in the test file, I give it this piece of json:
{
"inventory": [
{"name": "mountain bike", "price": 251.0},
{"name": "red wagon", "price": 90.10},
{"name": "kinesis advantage", "price": 300.0},
{"name": "a ticket to Mars", "price": 1200000000.0}
]
}
Then query out inventory[*].price
, expecting [251,90.1,300,1.2e+09]
, but instead getting ["251","90.1","300","1.2e+09"]
.
I would like to avoid using reflection here, but I don't see another way to do this.
答案1
得分: 1
我很抱歉如果我误解了你的问题,但希望这能帮到你。
我认为你要么需要使用反射,要么使用类型切换(http://golang.org/doc/effective_go.html#type_switch,它可能在幕后使用反射,不确定)。
修改你现有的valueToString
函数来包含一个类型切换应该不难。可能将其重命名为convertValue
或其他更通用的名称,并在其中加入一个类型切换。如果值是int类型,则返回int,否则返回string。
例如:
func convertValue(value interface{}) (text string, i int, err error) { // 原来是valueToString
if value == nil && *printNulls == false {
return "", nil, nil
}
textBytes, err := json.Marshal(value)
if err != nil {
return "", nil, err
}
switch value := value.(type) {
default:
text = string(textBytes)
text = quotedString.ReplaceAllString(text, "$1")
return text, nil, nil
case int:
i = textBytes
return nil, i, nil
}
}
这样就能将除了类型切换检测到的int类型的值之外的所有内容都转换为字符串。
可能有更简洁的方法,但几乎肯定需要进行大量的代码重构。主要的缺点是现在你需要在使用值之前检查它是否为nil。
我不确定是否有办法使单个函数能够返回多种类型的值,因为我相当确定这会对类型安全性造成混乱。如果可能的话,我只能想象通过在函数定义中返回一个空接口来实现。听起来有点混乱。
编辑:查看Andrew Gerrand的博客文章http://blog.golang.org/2011/01/json-and-go.html,特别是底部关于解码通用数据的部分。这应该会有所帮助。
英文:
I apologise if i've misunderstood your question, but hopefully this helps.
I think that you're either going to have to use reflection or a type switch (http://golang.org/doc/effective_go.html#type_switch , which probably uses reflection behind the scenes, not sure on that).
It shouldn't be too hard to modify your existing valueToString
function to include a type switch. Possibly rename it to convertValue
or something more generic, and put a type switch in it. If the value is an int, return an int, else return a string.
For example:
func convertValue(value interface{}) (text string, i int, err error) { // Was valueToString
if value == nil && *printNulls == false {
return "", nil, nil
}
textBytes, err := json.Marshal(value)
if err != nil {
return "", nil, err
}
switch value := value.(type) {
default:
text = string(textBytes)
text = quotedString.ReplaceAllString(text, "$1")
return text, nil, nil
case int:
i = textBytes
return nil, i, nil
}
}
That will hopefully string()
everything except the values that the type switch detects as ints, which will be returned as they are.
There's probably a cleaner way of doing it, but it would almost certainly involve a large code refactor. The major downside is that now you need to check if a value is nil before using it.
I'm not sure if there's a way to make a single function able to return one value of various types as I'm pretty sure it would play havoc with type safety. If it is possible, I can only imagine doing it by returning an empty interface in the function definition. Sounds messy.
EDIT: Check out Andrew Gerrand's blog post http://blog.golang.org/2011/01/json-and-go.html , especially the bit near the bottom about decoding generic data. It should help.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论