Maxim Yefremov
Maxim Yefremov

Reputation: 14185

cannot use type interface {} as type person in assignment: need type assertion

I try to convert interface{} to struct person...

package main

import (
    "encoding/json"
    "fmt"
)

func FromJson(jsonSrc string) interface{} {
    var obj interface{}
    json.Unmarshal([]byte(jsonSrc), &obj)

    return obj
}

func main() {

    type person struct {
        Name string
        Age  int
    }
    json := `{"Name": "James", "Age": 22}`

    actualInterface := FromJson(json)

    fmt.Println("actualInterface")
    fmt.Println(actualInterface)

    var actual person

    actual = actualInterface // error fires here -------------------------------

    // -------------- type assertion always gives me 'not ok'
    // actual, ok := actualInterface.(person)
    // if ok {

    //  fmt.Println("actual")
    //  fmt.Println(actual)
    // } else {
    //  fmt.Println("not ok")
    //  fmt.Println(actual)
    // }
}

... But got error:

cannot use type interface {} as type person in assignment: need type assertion

To solve this error I tried to use type assertion actual, ok := actualInterface.(person) but always got not ok.

Playground link

Upvotes: 3

Views: 9472

Answers (2)

user4122236
user4122236

Reputation:

The usual way to handle this is to pass a pointer to the output value to your decoding helper function. This avoids type assertions in your application code.

package main

import (
    "encoding/json"
    "fmt"
)

func FromJson(jsonSrc string, v interface{}) error {
    return json.Unmarshal([]byte(jsonSrc), v)

}

func main() {
    type person struct {
        Name string
        Age  int
    }
    json := `{"Name": "James", "Age": 22}`

    var p person
    err := FromJson(json, &p)

    fmt.Println(err)
    fmt.Println(p)
}

Upvotes: 6

joshlf
joshlf

Reputation: 23617

Your problem is that you're creating an empty interface to begin with, and telling json.Unmarshal to unmarshal into it. While you've defined a person type, json.Unmarshal has no way of knowing that that's what you intend the type of the JSON to be. To fix this, move the definition of person to the top level (that is, move it out of the body of main), and changeFromJson` to this:

func FromJson(jsonSrc string) interface{} {
    var obj person{}
    json.Unmarshal([]byte(jsonSrc), &obj)

    return obj
}

Now, when you return obj, the interface{} that's returned has person as its underlying type. You can run this code on the Go Playground.

By the way, your code is a bit un-idiomatic. I left the original Playground link unmodified except for my corrections so that it wouldn't be needlessly confusing. If you're curious, here's a version that's cleaned up to be more idiomatic (including comments on why I made the changes I did).

Upvotes: 5

Related Questions