Перетворити інтерфейс {} на 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

Відповіді:


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

Дякую. це прекрасна відповідь.
Муктадір

29

Я припускаю: якщо ви надіслали значення JSON через браузер, то будь-яке надіслане вами число, яке буде типом float64, тому ви не можете отримати значення безпосередньо в 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області. Зверніть увагу, що ви повинні вказати a 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 значення буде плаваючим. У такому випадку використовуйте 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
}

-2

Найкраще уникати кастингу, оголосивши f правильним типом f, який відповідає JSON.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.