type checking custom interface{} is not working as expected

71 views
Skip to first unread message

Santhosh Kumar T

unread,
Feb 16, 2021, 2:47:24 AM2/16/21
to golang-nuts
I have a function call nextRow which returns []interface{}

i want to add support for json, since json value can be string, number which conflicts
with native types, i used following:
    type Json interface{}
and returning json values as:
    return Json(v)
but in type checking it fails.

i extract minimal code to explain my issue:

in the above example, it prints: v3 is myinterface
but v3 is regular interface{} not of type myinterface

could someone help in resolving the issue. 
Is this expected behavior. what can i do to workaround if so

thanks
Santhosh

Axel Wagner

unread,
Feb 16, 2021, 3:02:07 AM2/16/21
to Santhosh Kumar T, golang-nuts
An interface type-assertion asserts that the dynamic value in the interface (in this case it's `string`) implements the interface you are asserting (in this case `myinterface`). As `myinterface` has no methods, every value implements that interface.

In general, a type-assertion will assert things about the dynamic value stored in an interface. In that code, the dynamic value is `string` *either way*. In one case, you assign a `string` to `interface{}`, in the other you assign a `string` to `myinterface`. But both will ultimately store a `string`. That's also why your first case, using `mystring` works as expected - in that case, the dynamic type is `string` in one case and `mystring` in the other (note that the dynamic type is *always* a "concrete type", not an interface).

In general, ways to get around this is to either a) not use an interface, or b) give that interface a method only specific types implement, or c) store a `*myinterface` - it's a pointer, not an interface, thus a concrete type, which can be distinguished. However, in your case, neither of these strategies would likely be fruitful. The `json` package needs to know how to store the values it decodes and it won't be able to, if it doesn't have a concrete type or a `json.Unmarshaler`.

So in your specific case, you might want to consider using something like

type struct {
    s string
    n int64
    isString bool
}

and have that implement `json.Marshaler` and `json.Unmarshaler`.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/bcaa91b2-38ab-4713-93c6-34dd55792f4dn%40googlegroups.com.

Santhosh Kumar T

unread,
Feb 16, 2021, 3:21:04 AM2/16/21
to golang-nuts
I am not using either json.Marshaler or json.Unmarshaller

my project implements mysql binlog replication protocol

i have a method:   fn nextRow() []interafce{}
which returns values in row as slice.
the row might contain VARCHAR and JSON type columns in mysql table definition
if actual json value for a row is string, then nextRow() return a slice containing two strings
to distinguish i am trying to returns []interface{}{"value1", Json("value2")}
but this seems does not solve the issue, since user of my library cannot check if it is json value or not

thanks
Santhosh

Arnaud Delobelle

unread,
Feb 16, 2021, 3:28:58 AM2/16/21
to Santhosh Kumar T, golang-nuts
You need you Json type to be a concrete type, e.g. (if the underlying type is a string)

type Json string

Then users can try to assert that what they get is of concrete type Json

Cheers,

Arnaud

Santhosh Kumar T

unread,
Feb 16, 2021, 5:25:06 AM2/16/21
to golang-nuts
I change it to following:

type JSON struct{ Val interface{} }

thanks
Santhosh

Reply all
Reply to author
Forward
0 new messages