web-dev-qa-db-fra.com

Convertir l'interface {} en int

J'essaie d'obtenir une valeur d'un JSON et de la convertir en int, mais cela ne fonctionne pas et je ne sais pas comment le faire correctement.

Voici le message d'erreur:

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

Et le code:

    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
77
Nick

Au lieu de

iAreaId := int(val)

vous voulez un type assertion :

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

La raison pour laquelle vous ne pouvez pas convertir une valeur typée d'interface sont les suivantes:

Les conversions sont des expressions de la forme T(x)T est un type et x est une expression qui peut être convertie en type T.

...

Une valeur non constante x peut être convertie en type T dans l’un des cas suivants:

  1. x est assignable à T.
  2. le type de x et T ont des types sous-jacents identiques.
  3. le type de x et T sont des types de pointeur sans nom et leurs types de base de pointeur ont des types sous-jacents identiques.
  4. le type de x et T sont des types entiers ou à virgule flottante.
  5. le type de x et T sont deux types complexes.
  6. x est un entier ou une tranche d'octets ou de runes et T est un type de chaîne.
  7. x est une chaîne et T est une tranche d'octets ou de runes.

Mais

iAreaId := int(val)

est pas l’un des cas 1.-7.

144
zzzz

Je suppose: si vous avez envoyé la valeur JSON via un navigateur, le nombre que vous avez envoyé sera du type float64, de sorte que vous ne pouvez pas obtenir la valeur directement en golang.

Alors faites la conversion comme:

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

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

De cette façon, vous pouvez obtenir une valeur exacte de ce que vous vouliez.

20
Mujibur

Je suis tout à fait d’accord avec la réponse de zzzz s type et je la préfère fortement aux autres. Cela dit, voici ce que j'ai dû faire lorsque la méthode préférée n'a pas fonctionné ... (histoire longue liée à la sérialisation croisée des données). Vous pouvez même chaîner cela dans une instruction switch avec case errInt == nil et des expressions similaires.

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

Comme je l'ai dit plus haut, essayez d'abord type assertion avant d'essayer de cette façon. 

3
openwonk

Ajouter une autre réponse qui utilise switch... Il existe des exemples plus complets, mais cela vous en donnera l’idée. 

Par exemple, t devient le type de données spécifié dans chaque étendue case. Notez que vous devez fournir une case pour un seul type pour un type, sinon t reste une 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)
}
1
openwonk

Vous devez faire une assertion de type pour convertir votre interface {} en valeur int.

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

Plus d'informations sont disponibles .

0
Kabeer Shaikh

J'ai écrit une bibliothèque qui peut aider avec les conversions de types 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
Daniel Krom

La façon la plus simple je l'ai fait. Pas le meilleur moyen mais le plus simple, je sais comment.

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
Mo-Gang