将interface {}转换为int


97

我正在尝试从JSON获取值并将其转换为int,但它不起作用,而且我不知道如何正确地执行它。

这是错误消息:

...cannot convert val (type interface {}) to type int: need type assertion

和代码:

    var f interface{}
    err = json.Unmarshal([]byte(jsonStr), &f)
    if err != nil {
        utility.CreateErrorResponse(w, "Error: failed to parse JSON data.")
        return
    }

    m := f.(map[string]interface{})

    val, ok := m["area_id"]
    if !ok {
        utility.CreateErrorResponse(w, "Error: Area ID is missing from submitted data.")
        return
    }

    fmt.Fprintf(w, "Type = %v", val)   // <--- Type = float64
    iAreaId := int(val)                // <--- Error on this line.
    testName := "Area_" + iAreaId      // not reaching here

Answers:


193

代替

iAreaId := int(val)

你想要一个类型断言

iAreaId := val.(int)
iAreaId, ok := val.(int) // Alt. non panicking version 

您不能转换接口类型值的原因是参考规范部分中的以下规则:

转换是形式的表达式,T(x)其中T是类型,并且x是可以转换为类型T的表达式。

...

在以下任何一种情况下,可以将非恒定值x转换为类型T:

  1. x可分配给T。
  2. x的类型和T具有相同的基础类型。
  3. x的类型和T是未命名的指针类型,并且它们的指针基类型具有相同的基础类型。
  4. x的类型和T都是整数或浮点类型。
  5. x的类型和T都是复数类型。
  6. x是整数或字节或符文的片段,T是字符串类型。
  7. x是字符串,T是字节或符文的切片。

iAreaId := int(val)

任何情况下1.-7。


好答案!语言规范始终是寻找答案的最佳地方!
Hot.PxL 2014年

谢谢。这是一个很好的答案。
Muktadir

29

我假设:如果您通过浏览器发送了JSON值,那么您发送的任何数字都将是float64类型,因此您无法直接在golang中获取该值int。

转换也是如此:

//As that says: 
fmt.Fprintf(w, "Type = %v", val) // <--- Type = float64

var iAreaId int = int(val.(float64))

这样,您可以获得所需的确切价值。


你是100%正确的@Mujibur,但任何理由,因为有整数JSON规格类型
卡马尔

@kamal是因为JSON使用Javascript语法和定义。JavaScript仅支持64位浮点数。Ref#javascript.info
number

4

添加另一个使用的答案switch...那里有更全面的示例,但这将为您提供想法。

例如,t成为每个case范围内的指定数据类型。请注意,您case只需要为一个类型提供一个类型,否则t保持为interface

package main

import "fmt"

func main() {
    var val interface{} // your starting value
    val = 4

    var i int // your final value

    switch t := val.(type) {
    case int:
        fmt.Printf("%d == %T\n", t, t)
        i = t
    case int8:
        fmt.Printf("%d == %T\n", t, t)
        i = int(t) // standardizes across systems
    case int16:
        fmt.Printf("%d == %T\n", t, t)
        i = int(t) // standardizes across systems
    case int32:
        fmt.Printf("%d == %T\n", t, t)
        i = int(t) // standardizes across systems
    case int64:
        fmt.Printf("%d == %T\n", t, t)
        i = int(t) // standardizes across systems
    case bool:
        fmt.Printf("%t == %T\n", t, t)
        // // not covertible unless...
        // if t {
        //  i = 1
        // } else {
        //  i = 0
        // }
    case float32:
        fmt.Printf("%g == %T\n", t, t)
        i = int(t) // standardizes across systems
    case float64:
        fmt.Printf("%f == %T\n", t, t)
        i = int(t) // standardizes across systems
    case uint8:
        fmt.Printf("%d == %T\n", t, t)
        i = int(t) // standardizes across systems
    case uint16:
        fmt.Printf("%d == %T\n", t, t)
        i = int(t) // standardizes across systems
    case uint32:
        fmt.Printf("%d == %T\n", t, t)
        i = int(t) // standardizes across systems
    case uint64:
        fmt.Printf("%d == %T\n", t, t)
        i = int(t) // standardizes across systems
    case string:
        fmt.Printf("%s == %T\n", t, t)
        // gets a little messy...
    default:
        // what is it then?
        fmt.Printf("%v == %T\n", t, t)
    }

    fmt.Printf("i == %d\n", i)
}

对于case string,您可以使用strconv.ParseFloat(t, 32)然后将结果转换为int
JVE999

3

我全心全意地同意zzzz类型断言答案,与其他方式相比,我非常喜欢这种方式。就是说,当首选方法不起作用时,这就是我要做的……(与数据的交叉序列化有关的长话)。您甚至可以将其链接到switch带有case errInt == nil和类似表达式的语句中。

package main

import "fmt"
import "strconv"

func main() {
    var v interface{}
    v = "4"

    i, errInt := strconv.ParseInt(v.(string), 10, 64)

    if errInt == nil {
        fmt.Printf("%d is a int", i)
        /* do what you wish with "i" here */
    }
}

就像我在上面说的那样,请先尝试类型断言,然后再尝试这种方式。


如前所述,如果解析JSON,则值将为float。在这种情况下,请strconv.ParseFloat(v.(string), 64)改用。您可能还想更改变量名,例如errFloat
openwonk

0

为了更好地理解类型转换,请看下面的代码:

package main
import "fmt"
func foo(a interface{}) {
    fmt.Println(a.(int))  // conversion of interface into int
}
func main() {
    var a int = 10
    foo(a)
}

此代码执行完美,并将接口类型转换为int类型

对于接口类型为T且类型为T的表达式x,主表达式x。(T)断言x不是nil,并且存储在x中的值是T类型。符号x。(T)称为类型断言。更准确地说,如果T不是接口类型,则x。(T)断言x的动态类型与T的类型相同。在这种情况下,T必须实现x的(接口)类型。否则类型断言无效,因为x不可能存储类型T的值。如果T是接口类型,则x。(T)断言x的动态类型实现了接口T。

回到您的代码,这

iAreaId := val.(int)

应该工作良好。如果要检查转换时发生的错误,还可以将上面的行重写为

iAreaId, ok := val.(int)


0

我写了一个可以帮助类型转换的库 https://github.com/KromDaniel/jonson

js := jonson.New([]interface{}{55.6, 70.8, 10.4, 1, "48", "-90"})

js.SliceMap(func(jsn *jonson.JSON, index int) *jonson.JSON {
    jsn.MutateToInt()
    return jsn
}).SliceMap(func(jsn *jonson.JSON, index int) *jonson.JSON {
    if jsn.GetUnsafeInt() > 50{
        jsn.MutateToString()
    }
    return jsn
}) // ["55","70",10,1,48,-90]

0

我这样做的最简单方法。我知道这不是最好的方法,但最简单的方法。

import "fmt"

func main() {
    fmt.Print(addTwoNumbers(5, 6))
}

func addTwoNumbers(val1 interface{}, val2 interface{}) int {
    op1, _ := val1.(int)
    op2, _ := val2.(int)

    return op1 + op2
}


0

也许你需要

func TransToString(data interface{}) (res string) {
    switch v := data.(type) {
    case float64:
        res = strconv.FormatFloat(data.(float64), 'f', 6, 64)
    case float32:
        res = strconv.FormatFloat(float64(data.(float32)), 'f', 6, 32)
    case int:
        res = strconv.FormatInt(int64(data.(int)), 10)
    case int64:
        res = strconv.FormatInt(data.(int64), 10)
    case uint:
        res = strconv.FormatUint(uint64(data.(uint)), 10)
    case uint64:
        res = strconv.FormatUint(data.(uint64), 10)
    case uint32:
        res = strconv.FormatUint(uint64(data.(uint32)), 10)
    case json.Number:
        res = data.(json.Number).String()
    case string:
        res = data.(string)
    case []byte:
        res = string(v)
    default:
        res = ""
    }
    return
}

-2

最好通过声明f为与JSON对应的正确类型来避免强制转换。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.