Преобразовать интерфейс {} в int

100

Я пытаюсь получить значение из 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
Ник
источник

Ответы:

202

Вместо того

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.

zzzz
источник
Хороший ответ! Спецификация языка - всегда лучшее место для поиска ответа!
Hot.PxL
Спасибо. это прекрасный ответ.
Муктадир
30

Я предполагаю: если вы отправили значение JSON через браузер, то любое отправленное вами число будет иметь тип float64, поэтому вы не сможете получить значение напрямую int в golang.

Так что сделайте преобразование, например:

//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-битные числа с плавающей запятой. Ссылка № 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)
}
openwonk
источник
Для case stringвы можете использовать, strconv.ParseFloat(t, 32)а затем int
преобразовать
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 */
    }
}

Как я сказал выше, сначала попробуйте ввести assertion, прежде чем пытаться сделать это.

openwonk
источник
Как уже указывалось, при синтаксическом анализе JSON значение будет с плавающей точкой. В этом случае используйте 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.

Для выражения x типа интерфейса и типа T первичное выражение x. (T) утверждает, что x не равно нулю и что значение, хранящееся в 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

Вам нужно сделать утверждение типа для преобразования вашего интерфейса {} в значение типа int.

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

Доступна дополнительная информация .

Кабир Шейх
источник
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
}
Aierui
источник
-2

Лучше избегать приведения типов, объявляя f как f - правильный тип, соответствующий JSON.

Амнон
источник