แปลงอินเทอร์เฟซ {} เป็น int


100

ฉันกำลังพยายามหาค่าจาก JSON และแคสต์เป็น int แต่ไม่ได้ผลและฉันไม่รู้ว่าจะทำอย่างไรให้ถูกต้อง

นี่คือข้อความแสดงข้อผิดพลาด:

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

และรหัส:

    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

คำตอบ:


202

แทน

iAreaId := int(val)

คุณต้องการการยืนยันประเภท :

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

สาเหตุที่คุณไม่สามารถแปลงค่าที่พิมพ์อินเทอร์เฟซคือกฎเหล่านี้ในส่วนข้อมูลจำเพาะที่อ้างอิง:

การแปลงเป็นนิพจน์ของรูปแบบT(x)ที่Tเป็นประเภทและxเป็นนิพจน์ที่สามารถแปลงเป็นประเภท T ได้

...

ค่าที่ไม่คงที่ x สามารถแปลงเป็นประเภท T ได้ในกรณีเหล่านี้:

  1. x สามารถกำหนดให้กับ T.
  2. ประเภทของ x และ T มีประเภทพื้นฐานที่เหมือนกัน
  3. ประเภทของ x และ T เป็นประเภทตัวชี้ที่ไม่มีชื่อและประเภทฐานของตัวชี้มีประเภทพื้นฐานที่เหมือนกัน
  4. ประเภทของ x และ T เป็นทั้งชนิดจำนวนเต็มหรือทศนิยม
  5. ประเภทของ x และ T เป็นประเภทที่ซับซ้อนทั้งคู่
  6. x คือจำนวนเต็มหรือส่วนของไบต์หรือรูนและ T คือประเภทสตริง
  7. x คือสตริงและ T คือชิ้นส่วนของไบต์หรือรูน

แต่

iAreaId := int(val)

คือไม่ได้กรณีใดกรณี 1. -7


คำตอบที่ดี! ข้อกำหนดของภาษาเป็นสถานที่ที่ดีที่สุดในการค้นหาคำตอบเสมอ!
Hot.PxL

ขอบคุณ. มันเป็นคำตอบที่สวยงาม
มุกตาดีร์

30

ฉันสมมติว่า: หากคุณส่งค่า JSON ผ่านเบราว์เซอร์ตัวเลขใด ๆ ที่คุณส่งไปจะเป็นประเภท float64 ดังนั้นคุณจึงไม่สามารถรับค่า int โดยตรงใน golang ได้

ทำการแปลงเช่น:

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

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

วิธีนี้คุณจะได้รับมูลค่าที่แน่นอนตามที่คุณต้องการ


คุณถูก @Mujibur 100% แต่ด้วยเหตุผลใดก็ตามเนื่องจากมีประเภทจำนวนเต็มในข้อกำหนด JSON
kamal

@kamal นั่นเป็นเพราะ JSON ใช้ไวยากรณ์และคำจำกัดความของ Javascript JavaScript รองรับเฉพาะตัวเลขทศนิยม 64 บิต Ref # javascript.info/number
Mujibur

4

การเพิ่มคำตอบอื่นที่ใช้switch... มีตัวอย่างที่ครอบคลุมมากกว่านี้ แต่จะให้แนวคิด

ตัวอย่างเช่นtกลายเป็นชนิดข้อมูลที่ระบุภายในแต่ละcaseขอบเขต หมายเหตุคุณต้องระบุประเภทcaseสำหรับประเภทเดียวเท่านั้นมิฉะนั้นtจะยังคงเป็น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)
}

สำหรับcase stringคุณสามารถใช้strconv.ParseFloat(t, 32)แล้วส่งผลลัพธ์เป็นint
JVE999

3

ฉันเห็นด้วยอย่างยิ่งกับคำตอบยืนยันประเภทของzzzzและฉันชอบวิธีนั้นมากกว่าคนอื่น ที่กล่าวมานี่คือสิ่งที่ฉันต้องทำเมื่อวิธีการที่ต้องการไม่ได้ผล ... คุณสามารถเชื่อมโยงสิ่งนี้เข้ากับประโยคที่มีและนิพจน์ที่คล้ายกันได้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 */
    }
}

อย่างที่ฉันได้กล่าวไว้ข้างต้นลองพิมพ์ยืนยันก่อนที่จะลองวิธีนี้


ตามที่ระบุไว้หากแยกวิเคราะห์ JSON ค่าจะเป็นแบบลอย ในกรณีนั้นให้ใช้strconv.ParseFloat(v.(string), 64)แทน errFloatคุณอาจต้องการที่จะเปลี่ยนชื่อตัวแปรเกินไปพูด
openwonk

0

หากต้องการทำความเข้าใจเกี่ยวกับการแปลงประเภทให้ดีขึ้นให้ดูที่โค้ดด้านล่าง

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

รหัสนี้ดำเนินการอย่างสมบูรณ์แบบและแปลงประเภทอินเทอร์เฟซเป็นประเภท int

สำหรับนิพจน์ x ของประเภทอินเทอร์เฟซและประเภท T นิพจน์หลัก x (T) จะยืนยันว่า x ไม่ใช่ศูนย์และค่าที่จัดเก็บใน x เป็นประเภท T สัญกรณ์ x (T) เรียกว่าการยืนยันประเภท . อย่างแม่นยำยิ่งขึ้นถ้า T ไม่ใช่ประเภทอินเทอร์เฟซ x. (T) จะยืนยันว่าชนิดไดนามิกของ x เหมือนกับชนิด T ในกรณีนี้ T ต้องใช้ (อินเตอร์เฟส) ประเภท x; มิฉะนั้นการยืนยันประเภทจะไม่ถูกต้องเนื่องจากเป็นไปไม่ได้ที่ x จะจัดเก็บค่าประเภท T ถ้า T เป็นประเภทอินเทอร์เฟซ x (T) จะยืนยันว่าชนิดไดนามิกของ x ใช้อินเทอร์เฟซ T

กลับไปที่รหัสของคุณสิ่งนี้

iAreaId := val.(int)

ควรทำงานได้ดี หากคุณต้องการตรวจสอบข้อผิดพลาดที่เกิดขึ้นในขณะที่เกิดการแปลงคุณสามารถเขียนบรรทัดด้านบนอีกครั้งได้

iAreaId, ok := val.(int)


0

ฉันเขียนไลบรารีที่สามารถช่วยในการแปลงประเภท 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

วิธีที่ง่ายที่สุดที่ฉันทำนี้ ไม่ใช่วิธีที่ดีที่สุด แต่เป็นวิธีที่ง่ายที่สุดที่ฉันรู้

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

คุณต้องทำการยืนยันประเภทสำหรับการแปลงอินเทอร์เฟซของคุณ {} เป็นค่า int

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

ข้อมูลเพิ่มเติมสามารถใช้ได้


0

บางทีคุณอาจต้องการ

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

หลีกเลี่ยงการแคสต์โดยประกาศ f เป็น f ประเภทที่ถูกต้องเพื่อให้สอดคล้องกับ JSON

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.