Преобразовать интерфейс {} в int
Я пытаюсь получить значение из 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
12 ответов
Вместо
iAreaId := int(val)
Вы хотите утверждение типа:
iAreaId := val.(int)
iAreaId, ok := val.(int) // Alt. non panicking version
Причиной, по которой вы не можете преобразовать типизированное значение интерфейса, являются следующие правила в указанных частях спецификации:
Конверсии - это выражения вида
T(x)
гдеT
это тип иx
является выражением, которое можно преобразовать в тип T.
...
Непостоянное значение x может быть преобразовано в тип T в любом из следующих случаев:
- х присваивается Т.
- Тип X и T имеют идентичные базовые типы.
- Тип x и T являются безымянными типами указателей, и их базовые типы указателей имеют идентичные базовые типы.
- Тип x и T оба являются целочисленными или с плавающей точкой.
- Тип x и T оба являются сложными типами.
- x - целое число или фрагмент байтов или рун, а T - строковый тип.
- x - это строка, а T - фрагмент байтов или рун.
Но
iAreaId := int(val)
не является ни одним из случаев 1.-7.
Я предполагаю: если вы отправили значение JSON через браузер, то любое отправленное вами число будет иметь тип float64, поэтому вы не можете получить значение непосредственно через int в golang.
Так что преобразование, как:
//As that says:
fmt.Fprintf(w, "Type = %v", val) // <--- Type = float64
var iAreaId int = int(val.(float64))
Таким образом, вы можете получить точное значение, что вы хотели.
Добавление другого ответа, который использует 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)
}
Я искренне согласен с zzzz ответом 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 */
}
}
Как я уже говорил выше, попробуйте сначала ввести утверждение, прежде чем пытаться таким образом.
Вы можете использовать отражение, чтобы помочь вам определить тип, а затем преобразовать.
func i2num(a interface{}) (interface{}, error) { // interface to number
aValue := reflect.ValueOf(a)
switch aValue.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return aValue.Int(), nil
case reflect.Float32, reflect.Float64:
return aValue.Float(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return aValue.Uint(), nil
case reflect.Bool:
if a == true {
return 1, nil
}
return 0, nil
case reflect.String:
return strconv.ParseFloat(aValue.String(), 64)
default:
return nil, errors.New("type error")
}
}
Может тебе нужно
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
}
использоватьcast.ToInt(anyValue)
Мне это нужно, потому что неприятная конечная точка, которую мне нужно использовать, имеет ошибку и иногда возвращает целое число в виде строки, иногда как float64.
Вам нужно сделать утверждение типа для преобразования вашего интерфейса {} в значение типа int.
iAreaId := val.(int)
iAreaId, ok := val.(int)
Более подробная информация доступна.
Самый простой способ, которым я сделал это. Не самый лучший, но самый простой способ, которым я умею.
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
}
Чтобы лучше понять преобразование типов, посмотрите на код ниже:
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 не равно nil и что значение, хранящееся в x, имеет тип T. Обозначение x.(T) называется утверждением типа, Точнее, если T не является интерфейсным типом, x.(T) утверждает, что динамический тип x идентичен типу T. В этом случае T должен реализовать тип (interface) x; в противном случае утверждение типа является недопустимым, поскольку для x невозможно сохранить значение типа T. Если T является типом интерфейса, x.(T) утверждает, что динамический тип x реализует интерфейс T.
Возвращаясь к вашему коду, это
iAreaId := val.(int)
должно работать хорошо. Если вы хотите проверить, произошла ли ошибка во время преобразования, вы также можете переписать вышеуказанную строку как
iAreaId, ok := val.(int)
Я написал библиотеку, которая может помочь с преобразованием типов 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]
Лучше всего избегать приведения, объявляя f правильным f, чтобы соответствовать JSON.