Chuyển đổi giao diện {} thành int


97

Tôi đang cố gắng lấy một giá trị từ JSON và truyền nó sang int nhưng nó không hoạt động và tôi không biết làm thế nào để thực hiện đúng.

Đây là thông báo lỗi:

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

Và mã:

    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

Câu trả lời:


193

Thay vì

iAreaId := int(val)

bạn muốn một xác nhận kiểu :

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

Lý do tại sao bạn không thể chuyển đổi giá trị đã nhập giao diện là các quy tắc này trong phần thông số kỹ thuật được tham chiếu:

Chuyển đổi là biểu thức của biểu mẫu T(x) trong đó Tlà một kiểu và xlà một biểu thức có thể được chuyển đổi sang kiểu T.

...

Một giá trị không hằng số x có thể được chuyển đổi thành kiểu T trong bất kỳ trường hợp nào sau đây:

  1. x có thể gán cho T.
  2. kiểu của x và T có kiểu cơ bản giống hệt nhau.
  3. kiểu của x và T là kiểu con trỏ không tên và kiểu cơ sở con trỏ của chúng có kiểu cơ bản giống hệt nhau.
  4. kiểu của x và T đều là kiểu số nguyên hoặc dấu phẩy động.
  5. loại của x và T đều là loại phức tạp.
  6. x là một số nguyên hoặc một lát byte hoặc rune và T là một kiểu chuỗi.
  7. x là một chuỗi và T là một phần của byte hoặc rune.

Nhưng

iAreaId := int(val)

không phải là bất kỳ trường hợp nào trong số 1.-7.


Câu trả lời tốt! Đặc tả ngôn ngữ luôn là nơi tốt nhất để tìm kiếm câu trả lời!
Hot.PxL

Cảm ơn. đó là một câu trả lời tuyệt vời.
Muktadir

29

Tôi giả sử: Nếu bạn gửi giá trị JSON qua trình duyệt thì bất kỳ số nào bạn đã gửi sẽ là loại float64, vì vậy bạn không thể nhận giá trị trực tiếp int trong golang.

Vì vậy, hãy thực hiện chuyển đổi như:

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

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

Bằng cách này, bạn có thể nhận được giá trị chính xác những gì bạn muốn.


Bạn đúng 100% @Mujibur, nhưng bất kỳ lý do gì, vì có kiểu số nguyên trong thông số JSON
kamal

@kamal đó là bởi vì JSON, sử dụng cú pháp và định nghĩa Javascript. JavaScript chỉ hỗ trợ số dấu phẩy động 64-bit. Tham khảo # javascript.info/number
Mujibur,

4

Thêm một câu trả lời khác sử dụng switch ... Có nhiều ví dụ toàn diện hơn ở đó, nhưng điều này sẽ cung cấp cho bạn ý tưởng.

Ví dụ, ttrở thành kiểu dữ liệu được chỉ định trong mỗi casephạm vi. Lưu ý, bạn phải cung cấp casechỉ cho một loại tại một loại, nếu không thì tvẫn là mộ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)
}

Đối với case string, bạn có thể sử dụng strconv.ParseFloat(t, 32)và sau đó truyền kết quả thànhint
JVE999

3

Tôi hoàn toàn đồng ý với câu trả lời khẳng định kiểu của zzzz và tôi thực sự thích cách đó hơn những cách khác. Điều đó nói rằng, đây là những gì tôi phải làm khi phương pháp ưa thích không hoạt động ... (câu chuyện dài liên quan đến tuần tự hóa chéo dữ liệu). Bạn thậm chí có thể chuỗi điều này thành một câu lệnh với và các biểu thức tương tự.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 */
    }
}

Giống như tôi đã nói ở trên, hãy thử gõ xác nhận trước khi thử theo cách này.


Như đã chỉ ra, nếu phân tích cú pháp JSON, giá trị sẽ là float. Trong trường hợp đó, hãy sử dụng strconv.ParseFloat(v.(string), 64)thay thế. Bạn cũng có thể muốn thay đổi tên biến, chẳng hạn như errFloat.
openwonk

0

Để hiểu rõ hơn về chuyển đổi loại, hãy xem đoạn mã dưới đây:

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

Mã này thực thi hoàn hảo và chuyển đổi kiểu giao diện thành kiểu int

Đối với biểu thức x thuộc kiểu giao diện và kiểu T, biểu thức chính x. (T) khẳng định rằng x không phải là nil và giá trị được lưu trữ trong x thuộc kiểu T. Kí hiệu x. (T) được gọi là khẳng định kiểu . Chính xác hơn, nếu T không phải là một kiểu giao diện, x. (T) khẳng định rằng kiểu động của x giống với kiểu T. Trong trường hợp này, T phải triển khai kiểu (giao diện) của x; nếu không thì khẳng định kiểu không hợp lệ vì x không thể lưu trữ giá trị kiểu T. Nếu T là một kiểu giao diện, x. (T) khẳng định rằng kiểu động của x thực hiện giao diện T.

Quay lại mã của bạn, cái này

iAreaId := val.(int)

nên hoạt động tốt. Nếu bạn muốn kiểm tra lỗi xảy ra trong khi chuyển đổi, bạn cũng có thể viết lại dòng trên dưới dạng

iAreaId, ok := val.(int)


0

Tôi đã viết một thư viện có thể trợ giúp chuyển đổi kiểu 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

Cách đơn giản nhất tôi đã làm điều này. Không phải là cách tốt nhất nhưng là cách đơn giản nhất mà tôi biết.

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

Bạn cần thực hiện xác nhận kiểu để chuyển đổi giao diện của mình {} thành giá trị int.

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

Nhiều thông tin có sẵn .


0

có thể bạn cần

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

Tốt nhất hãy tránh ép kiểu bằng cách khai báo f là kiểu chính xác để tương ứng với JSON.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.