128

我正在尝试从 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
4

11 回答 11

246

代替

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。

于 2013-08-04T09:32:18.017 回答
45

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

像这样进行转换:

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

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

这样你就可以得到你想要的确切价值。

于 2015-04-17T04:30:28.067 回答
5

我全心全意地同意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 */
    }
}

就像我上面说的,在尝试这种方式之前先尝试类型断言。

于 2015-07-04T08:40:58.557 回答
5

添加另一个使用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)
}
于 2018-10-16T00:59:17.943 回答
1

也许你需要

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
}
于 2020-07-08T05:59:10.870 回答
0

您需要进行类型断言以将您的 interface{} 转换为 int 值。

iAreaId := val.(int)
iAreaId, ok := val.(int)

提供更多信息

于 2018-01-23T02:59:41.993 回答
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]
于 2018-05-14T09:29:40.473 回答
0

您可以使用反射来帮助您确定类型,然后进行转换。

func i2num(a interface{}) (interface{}, error) { // interface to number
    aValue := reflect.ValueOf(a)
    switch aValue.Kind() {
    case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
        return aValue.Int(), nil
    case reflect.Float32, reflect.Float64:
        return aValue.Float(), nil
    case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
        return aValue.Uint(), nil
    case reflect.Bool:
        if a == true {
            return 1, nil
        }
        return 0, nil
    case reflect.String:
        return strconv.ParseFloat(aValue.String(), 64)
    default:
        return nil, errors.New("type error")
    }
}

去游乐场

于 2021-07-04T18:05:13.730 回答
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
}
于 2018-06-20T10:22:10.147 回答
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 类型

对于接口类型的表达式 x 和类型 T,主表达式 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)

于 2017-10-17T10:26:50.587 回答
-2

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

于 2018-01-07T21:04:14.013 回答