I want to check whether an received item of type any
implements encoding.TextUnmarshaller
. The problem is, it’s method must be a pointer receiver, and this seems to be the source of quite some trouble.
<code>
type MyStruct struct{ value string }
var _ encoding.TextMarshaler = (*MyStruct)(nil)
func (id MyStruct) MarshalText() (text []byte, err error) {
return []byte(id.value), nil
}
var _ encoding.TextUnmarshaler = (*MyStruct)(nil)
func (id *MyStruct) UnmarshalText(data []byte) error {
*id = MyStruct{value: string(data)}
return nil
}
func TestMyStruct(t *testing.T) {
var ms any = MyStruct{value: "hello"} // ms comes from elsewhere
_, ok := (ms).(encoding.TextMarshaler) // this will work b/c MyStruct is no pointer receiver here
assert.True(t, ok)
//_, ok = (ms).(encoding.TextUnmarshaler)
//assert.True(t, ok) // this will fail b/c MyStruct is is a pointer receiver here
v := reflect.ValueOf(ms)
if assert.True(t, v.Type().NumMethod() > 0 && v.CanInterface()) {
if v.CanAddr() { // it cannot
_, ok := v.Addr().Interface().(encoding.TextUnmarshaler)
assert.True(t, ok)
} else {
t.FailNow() // this is where I end up
}
}
}
</code>
<code>
type MyStruct struct{ value string }
var _ encoding.TextMarshaler = (*MyStruct)(nil)
func (id MyStruct) MarshalText() (text []byte, err error) {
return []byte(id.value), nil
}
var _ encoding.TextUnmarshaler = (*MyStruct)(nil)
func (id *MyStruct) UnmarshalText(data []byte) error {
*id = MyStruct{value: string(data)}
return nil
}
func TestMyStruct(t *testing.T) {
var ms any = MyStruct{value: "hello"} // ms comes from elsewhere
_, ok := (ms).(encoding.TextMarshaler) // this will work b/c MyStruct is no pointer receiver here
assert.True(t, ok)
//_, ok = (ms).(encoding.TextUnmarshaler)
//assert.True(t, ok) // this will fail b/c MyStruct is is a pointer receiver here
v := reflect.ValueOf(ms)
if assert.True(t, v.Type().NumMethod() > 0 && v.CanInterface()) {
if v.CanAddr() { // it cannot
_, ok := v.Addr().Interface().(encoding.TextUnmarshaler)
assert.True(t, ok)
} else {
t.FailNow() // this is where I end up
}
}
}
</code>
type MyStruct struct{ value string }
var _ encoding.TextMarshaler = (*MyStruct)(nil)
func (id MyStruct) MarshalText() (text []byte, err error) {
return []byte(id.value), nil
}
var _ encoding.TextUnmarshaler = (*MyStruct)(nil)
func (id *MyStruct) UnmarshalText(data []byte) error {
*id = MyStruct{value: string(data)}
return nil
}
func TestMyStruct(t *testing.T) {
var ms any = MyStruct{value: "hello"} // ms comes from elsewhere
_, ok := (ms).(encoding.TextMarshaler) // this will work b/c MyStruct is no pointer receiver here
assert.True(t, ok)
//_, ok = (ms).(encoding.TextUnmarshaler)
//assert.True(t, ok) // this will fail b/c MyStruct is is a pointer receiver here
v := reflect.ValueOf(ms)
if assert.True(t, v.Type().NumMethod() > 0 && v.CanInterface()) {
if v.CanAddr() { // it cannot
_, ok := v.Addr().Interface().(encoding.TextUnmarshaler)
assert.True(t, ok)
} else {
t.FailNow() // this is where I end up
}
}
}
Is there any (idiomatic) way to achieve that?