Ubah antarmuka {} menjadi int

100

Saya mencoba mendapatkan nilai dari JSON dan memasukkannya ke int tetapi tidak berhasil, dan saya tidak tahu cara melakukannya dengan benar.

Inilah pesan kesalahannya:

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

Dan kodenya:

    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
sumber

Jawaban:

202

Dari pada

iAreaId := int(val)

Anda menginginkan pernyataan tipe :

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

Alasan mengapa Anda tidak dapat mengonversi nilai yang diketik antarmuka adalah karena aturan ini di bagian spesifikasi yang direferensikan:

Konversi adalah ekspresi dari bentuk T(x)mana Tadalah tipe dan xmerupakan ekspresi yang dapat dikonversi untuk mengetik T.

...

Nilai x yang tidak konstan dapat diubah menjadi tipe T dalam salah satu kasus berikut:

  1. x dapat dialihkan ke T.
  2. tipe x dan T memiliki tipe dasar yang identik.
  3. tipe x dan T adalah tipe pointer tanpa nama dan tipe basis pointernya memiliki tipe dasar yang identik.
  4. tipe x dan T keduanya tipe integer atau floating point.
  5. tipe x dan T keduanya merupakan tipe kompleks.
  6. x adalah integer atau sepotong byte atau rune dan T adalah tipe string.
  7. x adalah string dan T adalah potongan byte atau rune.

Tapi

iAreaId := int(val)

adalah tidak salah satu kasus 1.-7.

zzzz
sumber
Jawaban yang bagus! Spesifikasi bahasa selalu menjadi tempat terbaik untuk mencari jawaban!
Hot.PxL
Terima kasih. itu jawaban yang bagus.
Muktadir
30

Saya berasumsi: Jika Anda mengirim nilai JSON melalui browser maka nomor yang Anda kirim itu akan menjadi tipe float64 sehingga Anda tidak bisa mendapatkan nilai langsung int di golang.

Jadi lakukan konversi seperti:

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

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

Dengan cara ini Anda bisa mendapatkan nilai yang Anda inginkan.

Mujibur
sumber
Anda 100% benar @Mujibur, tetapi alasan apa pun, karena ada tipe bilangan bulat dalam spesifikasi JSON
kamal
@kamal itu karena JSON, menggunakan sintaks dan definisi Javascript. JavaScript hanya mendukung angka floating point 64-bit. Ref # javascript.info/number
Mujibur
4

Menambahkan jawaban lain yang menggunakan switch... Ada contoh yang lebih komprehensif di luar sana, tapi ini akan memberi Anda gambaran.

Misalnya, tmenjadi tipe data yang ditentukan dalam setiap casecakupan. Catatan, Anda harus menyediakan casehanya untuk satu tipe pada satu tipe, jika tidak ttetap sebuah 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
sumber
Untuk case string, Anda dapat menggunakan strconv.ParseFloat(t, 32)dan kemudian mengirimkan hasilnya keint
JVE999
3

Aku sepenuh hati setuju dengan zzzz 's jenis pernyataan jawaban dan saya sangat suka dengan cara itu atas orang lain. Yang mengatakan, inilah yang harus saya lakukan ketika metode yang disukai tidak berhasil ... (cerita panjang terkait dengan lintas serialisasi data). Anda bahkan dapat merangkai ini menjadi switchpernyataan dengan case errInt == nildan ekspresi serupa.

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

Seperti yang saya katakan di atas, coba ketik pernyataan terlebih dahulu sebelum mencoba cara ini.

openwonk
sumber
Seperti yang ditunjukkan, jika mengurai JSON, nilainya akan mengambang. Dalam hal ini, gunakan strconv.ParseFloat(v.(string), 64)saja. Anda mungkin ingin mengubah nama variabel juga, katakanlah errFloat.
openwonk
0

Untuk lebih memahami jenis konversi, lihat kode di bawah ini:

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

Kode ini dijalankan dengan sempurna dan mengubah tipe antarmuka menjadi tipe int

Untuk ekspresi x dari tipe antarmuka dan tipe T, ekspresi utama x. (T) menegaskan bahwa x bukan nil dan bahwa nilai yang disimpan dalam x adalah tipe T. Notasi x. (T) disebut sebagai pernyataan tipe . Lebih tepatnya, jika T bukan tipe antarmuka, x. (T) menegaskan bahwa tipe dinamis x identik dengan tipe T. Dalam kasus ini, T harus mengimplementasikan tipe (antarmuka) x; jika tidak, pernyataan tipe tidak valid karena tidak mungkin bagi x untuk menyimpan nilai tipe T. Jika T adalah tipe antarmuka, x. (T) menegaskan bahwa tipe dinamis x mengimplementasikan antarmuka T.

Kembali ke kode Anda, ini

iAreaId := val.(int)

harus bekerja dengan baik. Jika Anda ingin memeriksa kesalahan yang terjadi saat konversi, Anda juga dapat menulis ulang baris di atas sebagai

iAreaId, ok := val.(int)

Bijendra Kumar
sumber
0

Saya menulis perpustakaan yang dapat membantu dengan jenis konversi 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
sumber
0

Cara paling sederhana saya melakukan ini. Bukan cara terbaik tapi cara paling sederhana yang saya tahu caranya.

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
}
Godfrey
sumber
0

Anda perlu melakukan pernyataan tipe untuk mengubah antarmuka Anda {} menjadi nilai int.

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

Informasi lebih lanjut tersedia .

Kabeer Shaikh
sumber
0

mungkin kamu butuh

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
sumber
-2

Sebaiknya hindari casting dengan menyatakan f sebagai f adalah tipe yang benar untuk menyesuaikan dengan JSON.

Amnon
sumber