在递归的golang函数调用中输入

huangapple go评论85阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2013年5月15日 11:05:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/16556112.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定