将字符串转换为最合适的类型

I'm aware that using the strconv package, one can parse a string to whatever type they need. However, with the program I'm making, I won't know the optimal type of the variable I need to parse at runtime. Is there a better way to do this than the one I have? (My code is ugly, terrible, and awful. I really want to figure out a better solution.)

relevant code

import(
    "strconv"
    "fmt"
)

type object interface{}

func parse(raw string,block int) object{
    if block==0{
        if raw=="true"{
            return true
        }else if raw=="false"{
            return false
        }else{
            parse(raw,block+1)
        }
    }else if block==1{
        res,err:=strconv.ParseFloat(raw,64)
        if err!=nil{parse(raw,block+1)}
        return res
    }else if block==2{
        res,err:=strconv.ParseInt(raw,10,64)
        if err!=nil{parse(raw,block+1)}
        return res
    }
    return raw
}

edit: using the object type blocks me from using the returned value in it's type, so that needs to go, too.

Edit

The original example was correct but wasn't all that helpful, and it didn't satisfy the OP's requirements. I've since updated the answer so that it works in the given context... and I hope it is also helpful.

You can return an interface{} and then switch on the return type, something like this:

package main

import "strconv"

func parse(raw string, block int) interface{} {
    if block == 0 {
        if raw == "true" || raw == "false" {
            if ok, err := strconv.ParseBool(raw); err == nil {
                return ok
            }
        } 
        return parse(raw, block+1)

    } else if block == 1 {
        if res, err := strconv.ParseInt(raw, 10, 64); err == nil {
            return res
        }
        return parse(raw, block+1)

    } else if block == 2 {
        if res, err := strconv.ParseFloat(raw, 64); err == nil {
            return res
        }
        return parse(raw, block+1)
    }
    return raw
}

func main() {
    a := parse("10.1", 0)
    switch a.(type) {
    case bool:
        //do something with a.(bool))
    case float64:
        //do something with a.(float64))
    case int64:
        //do something with a.(int64))
    case string:
        // do something with a.(string)
    }
}

Notable differences between this and your original example:

  • You have to return that semi-recursive function call, not merely call it, else you eventually return raw unless your first case (block == 0) returns.

  • It is necessary to check ParseInt() before ParseFloat() as an int can always satisfy the conditions of a float, not the other way around however.

  • Unless you need methods on the return type you can simply return interface{}, and there is no need to declare a type.

  • And finally, for no other reason than style, I opted for returning on err == nil vs. calling parse(raw, block+1) on err != nil; ultimately either get the same result.