键入递归golang函数调用

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.

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.