インターフェイス{}をintに変換します


97

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

回答:


193

の代わりに

iAreaId := int(val)

型アサーションが必要です:

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

インターフェース型付き値を変換できない理由は、参照される仕様の部分にある以下の規則です。

変換は、フォームの式であるタイプであり、T.型に変換することができる表現でありますT(x)Tx

...

非定数値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 2014

ありがとう。それは素晴らしい答えです。
Muktadir

29

私が想定しているのは、ブラウザーを介してJSON値を送信した場合、送信した任意の数値はfloat64型になるため、golangで直接値を取得することはできません。

だから変換は次のようにします:

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

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

このようにして、あなたが望むものを正確に得ることができます。


あなたは100%正しい@Mujiburですが、JSON仕様には整数型があるため、理由は何
ですか

@kamalは、JSONがJavaScriptの構文と定義を使用しているためです。JavaScriptは64ビット浮動小数点数のみをサポートしています。参照番号javascript.info/number
ムジバー

4

を使用する別の回答を追加しますswitch...より包括的な例がそこにありますが、これはあなたにアイデアを与えます。

例でtは、各caseスコープ内で指定されたデータ型になります。注意は、あなたが提供する必要がありcaseそうでない場合は、タイプに1つのだけのタイプのために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タイプアサーションの回答に心から同意し、他の方法よりもその方法を強く望んでいます。そうは言っても、推奨される方法が機能しない場合に私がしなければならなかったことはここにあります...(データのクロスシリアル化に関連する長い話)これを、同様の式を持つswitchステートメントにチェーンすることもできcase 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型に変換します

インターフェイスタイプとタイプTの式xの場合、1次式x。(T)は、xがnilではなく、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

多分あなたは必要です

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

JSONに対応する正しい型をfとして宣言することにより、キャストを回避することをお勧めします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.