Convertir l'interface {} en int

97

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
pseudo
la source

Réponses:

193

Au lieu de

iAreaId := int(val)

vous voulez une assertion de type :

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 ces règles dans les parties de spécifications référencées:

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

...

Une valeur non constante x peut être convertie en type T dans l'un de ces cas:

  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. x et T sont tous deux des types entiers ou flottants.
  5. le type de x et T sont tous deux des 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.

zzzz
la source
Bonne réponse! La spécification de la langue est toujours le meilleur endroit pour chercher une réponse!
Hot.PxL
Merci. c'est une belle réponse.
Muktadir
29

Je suppose: si vous avez envoyé la valeur JSON via le navigateur, tout nombre que vous avez envoyé sera du type float64, vous ne pouvez donc pas obtenir la valeur directement int dans 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 la valeur exacte que vous vouliez.

Mujibur
la source
Vous avez 100% raison @Mujibur, mais quelle qu'en soit la raison, car il y a un type entier dans les spécifications JSON
kamal
@kamal c'est parce que JSON utilise la syntaxe et les définitions Javascript. JavaScript ne prend en charge que les nombres à virgule flottante 64 bits. Ref # javascript.info/number
Mujibur
4

Ajout d'une autre réponse qui utilise switch... Il existe des exemples plus complets, mais cela vous donnera l'idée.

Par exemple, tdevient le type de données spécifié dans chaque caseétendue. Remarque, vous devez fournir un casepour un seul type à un type, sinon treste 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)
}
openwonk
la source
Pour case string, vous pouvez utiliser strconv.ParseFloat(t, 32)puis int
convertir
3

Je suis entièrement d'accord avec la réponse d' affirmation de type de zzzz et je préfère fortement cette façon à d'autres. Cela dit, voici ce que j'ai dû faire lorsque la méthode préférée n'a pas fonctionné ... (longue histoire liée à la sérialisation croisée des données). Vous pouvez même l'enchaîner dans une instruction avec des expressions similaires.switchcase 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 */
    }
}

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

openwonk
la source
Comme indiqué, si vous analysez JSON, la valeur sera float. Dans ce cas, utilisez à la strconv.ParseFloat(v.(string), 64)place. Vous pouvez également changer les noms de variables, par exemple errFloat.
openwonk
0

Pour mieux comprendre la conversion de type, regardez le code ci-dessous:

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

Ce code s'exécute parfaitement et convertit le type d'interface en type int

Pour une expression x de type interface et de type T, l'expression primaire x. (T) affirme que x n'est pas nul et que la valeur stockée dans x est de type T. La notation x. (T) est appelée une assertion de type . Plus précisément, si T n'est pas un type d'interface, x. (T) affirme que le type dynamique de x est identique au type T. Dans ce cas, T doit implémenter le type (d'interface) de x; sinon, l'assertion de type est invalide car il n'est pas possible pour x de stocker une valeur de type T. Si T est un type d'interface, x. (T) affirme que le type dynamique de x implémente l'interface T.

Revenons à votre code, ceci

iAreaId := val.(int)

devrait bien fonctionner. Si vous voulez vérifier l'erreur survenue lors de la conversion, vous pouvez également réécrire la ligne ci-dessus comme

iAreaId, ok := val.(int)

Bijendra Kumar
la source
0

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

La manière la plus simple que j'ai faite. Pas la meilleure façon mais la plus simple que je connaisse.

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
}
Mo-Gang
la source
0

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 .

Kabeer Shaikh
la source
0

peut-être avez-vous besoin

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
la source
-2

Il vaut mieux éviter le cast en déclarant f comme étant f le type correct pour correspondre au JSON.

Amnon
la source