Converti l'interfaccia {} in int


97

Sto cercando di ottenere un valore da un JSON e di trasmetterlo a int ma non funziona e non so come farlo correttamente.

Ecco il messaggio di errore:

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

E il codice:

    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

Risposte:


193

Invece di

iAreaId := int(val)

vuoi un'asserzione di tipo :

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

Il motivo per cui non è possibile convertire un valore digitato dall'interfaccia sono queste regole nelle parti delle specifiche di riferimento:

Le conversioni sono espressioni della forma in T(x)cui Tè un tipo ed xè un'espressione che può essere convertita nel tipo T.

...

Un valore x non costante può essere convertito nel tipo T in uno qualsiasi di questi casi:

  1. x è assegnabile a T.
  2. Il tipo di x e T hanno tipi sottostanti identici.
  3. Il tipo di x e T sono tipi di puntatore senza nome ei loro tipi di base del puntatore hanno tipi sottostanti identici.
  4. Il tipo di x e T sono entrambi tipi interi o in virgola mobile.
  5. Il tipo di x e T sono entrambi tipi complessi.
  6. x è un numero intero o una fetta di byte o rune e T è un tipo stringa.
  7. x è una stringa e T è una fetta di byte o rune.

Ma

iAreaId := int(val)

non è uno dei casi 1.-7.


Buona risposta! Le specifiche della lingua sono sempre il posto migliore per cercare una risposta!
Hot.PxL

Grazie. è una bellissima risposta.
Muktadir

29

Suppongo: se hai inviato il valore JSON tramite il browser, qualsiasi numero che hai inviato sarà il tipo float64, quindi non puoi ottenere il valore direttamente int in golang.

Quindi fai la conversione come:

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

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

In questo modo puoi ottenere il valore esatto che volevi.


Hai ragione al 100% @ Mujibur, ma qualsiasi motivo, poiché nelle specifiche JSON è presente un tipo intero
kamal

@kamal è perché JSON, utilizza la sintassi e le definizioni Javascript. JavaScript supporta solo numeri in virgola mobile a 64 bit. Ref # javascript.info/number
Mujibur

4

Aggiungendo un'altra risposta che usa switch... Ci sono esempi più completi là fuori, ma questo ti darà l'idea.

Ad esempio, tdiventa il tipo di dati specificato all'interno di ogni caseambito. Nota, devi fornire un caseper un solo tipo in un tipo, altrimenti trimane un 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)
}

Per case string, puoi usare strconv.ParseFloat(t, 32)e quindi int
trasmettere

3

Con tutto il cuore d'accordo con zzzz 's tipo di affermazione risposta e preferisco fortemente in questo modo sugli altri. Detto questo, ecco cosa ho dovuto fare quando il metodo preferito non ha funzionato ... (lunga storia relativa alla serializzazione incrociata dei dati). Puoi anche concatenarlo in una switchdichiarazione con case errInt == nilespressioni simili.

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 */
    }
}

Come ho detto sopra, prova l' asserzione del tipo prima di provare in questo modo.


Come sottolineato, se si analizza JSON, il valore sarà float. In tal caso, usa strconv.ParseFloat(v.(string), 64)invece. Potresti voler cambiare anche i nomi delle variabili, ad esempio errFloat.
openwonk

0

Per comprendere meglio la conversione del tipo, guarda il codice seguente:

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)
}

Questo codice viene eseguito perfettamente e converte il tipo di interfaccia in tipo int

Per un'espressione x di tipo interfaccia e un tipo T, l'espressione primaria x. (T) afferma che x non è nullo e che il valore memorizzato in x è di tipo T. La notazione x. (T) è chiamata asserzione di tipo . Più precisamente, se T non è un tipo di interfaccia, x. (T) asserisce che il tipo dinamico di x è identico al tipo T. In questo caso, T deve implementare il tipo (interfaccia) di x; altrimenti l'asserzione di tipo non è valida poiché non è possibile per x memorizzare un valore di tipo T. Se T è un tipo di interfaccia, x. (T) afferma che il tipo dinamico di x implementa l'interfaccia T.

Tornando al tuo codice, questo

iAreaId := val.(int)

dovrebbe funzionare bene. Se vuoi controllare che si sia verificato un errore durante la conversione, puoi anche riscrivere la riga sopra come

iAreaId, ok := val.(int)


0

Ho scritto una libreria che può aiutare con le conversioni di tipo 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

Il modo più semplice l'ho fatto. Non il modo migliore, ma il modo più semplice che conosco.

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

Devi eseguire un'asserzione di tipo per convertire la tua interfaccia {} in un valore int.

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

Sono disponibili ulteriori informazioni .


0

forse hai bisogno

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

È meglio evitare il casting dichiarando che f è il tipo corretto per corrispondere al JSON.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.