简体   繁体   中英

Interface variable conversion in Golang

I have a variable which value can be string or int depend on the input. I use interface{} as the type. How to convert the value of that variable to int if the input is like "50" , "45" , or any string of int.

package main

import "fmt"
import "log"
import "strconv"

func main() {
  var limit interface{}
  limit = "50"
  page := 1
  offset := 0
  if limit != "ALL" {
        log.Println("INSIDE")
        offset = limit.(int)*page - limit.(int)
    }
    fmt.Println(offset)
}

Above code got:

interface conversion: interface {} is string, not int

If I use this:

package main

import "fmt"
import "log"
import "strconv"

func main() {
  var limit interface{}
  limit = "50"
  page := 1
  offset := 0
  if limit != "ALL" {
        log.Println("INSIDE")
        offset = strconv.Atoi(limit)*page - strconv.Atoi(limit)
    }
  fmt.Println(offset)
}

I got this

exit status 2
 command-line-arguments
./main.go:14:24: cannot use limit (type interface {}) as type string in argument to strconv.Atoi: need type assertion
./main.go:14:24: multiple-value strconv.Atoi() in single-value context
./main.go:14:51: cannot use limit (type interface {}) as type string in argument to strconv.Atoi: need type assertion
./main.go:14:51: multiple-value strconv.Atoi() in single-value context

How to convert value of that variable to int?

In Go, in contrast to languages such as Python/JavaScript/Perl, the variables have strict types and strong boundaries. You have to write explicit code to make the conversion of a string from/to an integer. This is helpful to write safer and more performant programs.

In addition, if the variable is stored in an interface{} you have to use a type assertion (or a type switch) to further use the content with a specific type.

Here is your fixed code :

package main

import "fmt"
import "log"
import "strconv"

func main() {
    var limit interface{}
    limit = "50"
    page := 1
    offset := 3
    if limit != "ALL" {
        // Type assertion
        s, isString := limit.(string)
        if !isString {
            log.Fatalf("limit is not a string but %T", limit)
        }
        // Conversion from string to int, with error handling
        l, err := strconv.Atoi(s)
        if err != nil {
            log.Fatalf("%s: %v", limit, err)
        }
        offset = l*page - l
    }
    fmt.Println(offset)
}

However, I suggest that you just use the string type for the limit variable.

strconv package can use for this kind of conversion

package main

import (
    "fmt"
    "strconv"
)

func main() {
    var lim interface{}
    lim = "10"
    fmt.Printf("Type is: %T\nValue is: %s \n", lim, lim.(string))
    i, _ := strconv.Atoi(lim.(string))
    fmt.Printf("After conversion value is: %d", i)
}

Output of the above code:

Type is: string, Value is: 10 After conversion value is: 10

As I understood your question, value of your limit in fact is always string, but in one case it's value == ALL , otherwise it's a string representation of an integer value.

If I'm right, then I would provide following solution:

import (
    "errors"
    "fmt"
    "strconv"
)

func getOffset(limit string, page int64) (int64, error) {
    lim, err := strconv.ParseInt(limit, 10, 64)
    if err != nil {
        if limit == "ALL" {
            return 0, nil
        }

        return 0, errors.New(fmt.Sprintf("string '%v' doesn't fit requirements, error: %v", limit, err))
    }

    offset := lim*page - lim
    return offset, nil
}

Full solution on playground: https://play.golang.org/p/fJv9_cw18R5

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM