Konvertieren Sie die Schnittstelle {} in int

97

Ich versuche, einen Wert von einem JSON abzurufen und in int umzuwandeln, aber es funktioniert nicht und ich weiß nicht, wie ich es richtig machen soll.

Hier ist die Fehlermeldung:

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

Und der 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
Nick
quelle

Antworten:

189

Anstatt

iAreaId := int(val)

Sie möchten eine Typzusicherung :

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

Der Grund, warum Sie einen vom Typ Schnittstelle eingegebenen Wert nicht konvertieren können, sind die folgenden Regeln in den angegebenen Spezifikationsteilen:

Konvertierungen sind Ausdrücke der Form, T(x)bei der Tes sich um einen Typ handelt und xdie in Typ T konvertiert werden können.

...

Ein nicht konstanter Wert x kann in einem der folgenden Fälle in Typ T konvertiert werden:

  1. x ist T zuweisbar.
  2. x-Typ und T haben identische zugrunde liegende Typen.
  3. x-Typ und T sind unbenannte Zeigertypen und ihre Zeigerbasistypen haben identische zugrunde liegende Typen.
  4. x-Typ und T sind sowohl Ganzzahl- als auch Gleitkommatypen.
  5. x-Typ und T sind beide komplexe Typen.
  6. x ist eine Ganzzahl oder eine Schicht von Bytes oder Runen und T ist ein Zeichenfolgentyp.
  7. x ist eine Zeichenfolge und T ist eine Scheibe von Bytes oder Runen.

Aber

iAreaId := int(val)

ist nicht jeder des Falles 1.-7.

zzzz
quelle
Gute Antwort! Sprachspezifikation ist immer der beste Ort, um nach einer Antwort zu suchen!
Hot.PxL
Vielen Dank. Es ist eine schöne Antwort.
Muktadir
29

Ich gehe davon aus: Wenn Sie den JSON-Wert über den Browser gesendet haben, ist jede Nummer, die Sie gesendet haben, vom Typ float64, sodass Sie den Wert nicht direkt in golang erhalten können.

So macht die Konvertierung wie:

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

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

Auf diese Weise erhalten Sie genau den Wert, den Sie wollten.

Mujibur
quelle
Sie haben 100% Recht @Mujibur, aber jeder Grund, da es in Integer-Typ in JSON-Spezifikationen gibt
Kamal
@kamal, weil JSON Javascript-Syntax und -Definitionen verwendet. JavaScript unterstützt nur 64-Bit-Gleitkommazahlen. Ref # javascript.info/number
Mujibur
4

Hinzufügen einer weiteren Antwort, die verwendet switch... Es gibt umfassendere Beispiele, aber dies gibt Ihnen die Idee.

Wird beispielsweise tder angegebene Datentyp in jedem caseBereich. Beachten Sie, dass Sie casefür einen Typ nur einen Typ angeben müssen, andernfalls tbleibt ein 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
quelle
Für case string, können Sie strconv.ParseFloat(t, 32)und werfen dann das Ergebnis in eineint
JVE999
3

Ich von ganzem Herzen zustimmen zzzz ‚s Art Behauptung Antwort und ich ziehe stark auf diese Weise über andere. Das heißt, ich musste Folgendes tun, wenn die bevorzugte Methode nicht funktioniert hat ... (lange Geschichte im Zusammenhang mit der Kreuzserialisierung von Daten). Sie können dies sogar zu einer switchAnweisung mit case errInt == nilund ähnlichen Ausdrücken verketten.

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

Versuchen Sie, wie oben erwähnt, zuerst die Typzusicherung, bevor Sie dies versuchen.

openwonk
quelle
Wie bereits erwähnt, ist der Wert beim Parsen von JSON float. Verwenden Sie in diesem Fall strconv.ParseFloat(v.(string), 64)stattdessen. Möglicherweise möchten Sie auch Variablennamen ändern errFloat.
Openwonk
0

Ich habe eine Bibliothek geschrieben, die bei der Typkonvertierung https://github.com/KromDaniel/jonson helfen kann

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
quelle
0

Am einfachsten habe ich das gemacht. Nicht der beste Weg, aber der einfachste Weg, wie ich weiß.

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
quelle
0

Sie müssen eine Typzusicherung durchführen, um Ihre Schnittstelle {} in einen int-Wert zu konvertieren.

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

Weitere Informationen sind verfügbar .

Kabeer Shaikh
quelle
0

Vielleicht brauchst du

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
quelle
-1

Um die Typkonvertierung besser zu verstehen, sehen Sie sich den folgenden Code an:

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

Dieser Code wird perfekt ausgeführt und konvertiert den Schnittstellentyp in den Int-Typ

Für einen Ausdruck x vom Schnittstellentyp und einen Typ T behauptet der primäre Ausdruck x (T), dass x nicht Null ist und dass der in x gespeicherte Wert vom Typ T ist. Die Notation x (T) wird als Typzusicherung bezeichnet . Genauer gesagt, wenn T kein Schnittstellentyp ist, behauptet x. (T), dass der dynamische Typ von x mit dem Typ T identisch ist. In diesem Fall muss T den (Schnittstellen-) Typ von x implementieren; Andernfalls ist die Typzusicherung ungültig, da x keinen Wert vom Typ T speichern kann. Wenn T ein Schnittstellentyp ist, behauptet x (T), dass der dynamische Typ von x die Schnittstelle T implementiert.

Gehen Sie zurück zu Ihrem Code

iAreaId := val.(int)

sollte gut funktionieren. Wenn Sie überprüfen möchten, ob während der Konvertierung ein Fehler aufgetreten ist, können Sie die obige Zeile auch als neu schreiben

iAreaId, ok := val.(int)

Bijendra Kumar
quelle
-2

Vermeiden Sie am besten das Casting, indem Sie f als den richtigen Typ deklarieren, der dem JSON entspricht.

Amnon
quelle