John Balvin Arias
John Balvin Arias

Reputation: 2886

convert interface{} directly to int in Golang, where interface stores a number as string

I got a map[string]interface{} because decoding to JSON; with normal data, interface most be only a number but in type string, like this :

var a interface{}
a="3"

And then all data will be stored into a struct.

type someStruct struct {
   ID string
   Number1 int
   Number2 int
   Number3 int
   Number4 int
}

So I need to convert interface to int, but can´t do it easily and efficiently because only the code would be https://play.golang.org/p/oktbvTUbk93, pretty annoying and code does not seem to be readable if you take in mind the fact that I should handle all of possible errors

I would want to convert it directly to int, I´ve been searching for solutions but any of this convertions works as I want https://play.golang.org/p/Dw67U6kZwHC

In case you wondering why I don´t just decode it into struct directly, it´s because it´s dynamic data, the actual decoding occurs like this :

type dataIn struct {
   Code int         `json:"code"`
   ID   string      `json:"id"`
   Data interface{} `json:"data"`
}

And then I handle Data according to code and id, and they all are different data structures, so I can´t directly handle it with JSON

Upvotes: 0

Views: 6362

Answers (3)

icza
icza

Reputation: 417797

Create a helper function which does parsing and validating for you, in one place:

func parseInt(i interface{}) (int, error) {
    s, ok := i.(string)
    if !ok {
        return 0, errors.New("not string")
    }
    return strconv.Atoi(s)
}

And you can use this where needed. Here's a complete example, in which I also used another helper function, which takes care of the error handling:

m := map[string]interface{}{
    "number1": "1",
    "number2": "2",
    "number3": "3",
    "number4": "4",
    "ID":      "asdsa",
    "Title":   "asdas",
}

getInt := func(key string) int {
    n, err := parseInt(m[key])
    if err != nil {
        panic(err) // Decide what you wanna do with error
    }
    return n
}

// converting to struct
data := element{
    ID:      m["ID"].(string),
    Title:   m["Title"].(string),
    Number1: getInt("number1"),
    Number2: getInt("number2"),
    Number3: getInt("number3"),
    Number4: getInt("number4"),
}

fmt.Printf("%+v\n", data)

Output of the above (try it on the Go Playground):

{ID:asdsa Title:asdas Number1:1 Number2:2 Number3:3 Number4:4}

Also note that the open source package github.com/icza/dyno should help you handle dynamic objects at ease. (Disclosure: I'm the author.) It has a dyno.GetInteger() function for example, which is capable of extracting an int64 value out of multiple types (such as integers, floats, strings etc.).

Upvotes: 3

codehakase
codehakase

Reputation: 20

I still didn't get the part where you stated the struct is generated dynamically. Anyways, you can have a struct method attached, that does the int conversion. If the Data field, which is of type interface{} is always gonna hold integers, you an try this:

type DataIn struct {
  Code int         `json:"code"`
  ID   string      `json:"id"`
  Data interface{} `json:"data"`
}

func (s DataIn) toInt() int {
   switch t := s.Data.(type)
   case int:
     i, _ := strings.Atoi(fmt.Sprintf("%v",s.Data))
     return i
}

// using it
sampleData := someStruct{
  Number1: datain.toInt(),
}

Upvotes: 0

darkliquid
darkliquid

Reputation: 4109

Sounds like what you need is a custom unmarshal json method on your main struct. First, unmarshal into your main struct to get your code and id, then use those in a switch statement to determine which struct to use for the rest of the data and unmarshal into that, stirring that struct in your Data field.

Upvotes: 0

Related Questions