How to check if a value implements an interface - go

I want to compare my type by the specific way. For this purpose, I create the function MyType.Same(other MyType) bool for each type.
In some generic function, I want to check if the parameter has a function "Same" and invoke it if yes.
How can I do it in a generic way for different types?
type MyType struct {
MyField string
Id string // ignored by comparison
}
func (mt MyType) Same(other MyType) bool {
return mt.MyField == other.MyField
}
// MyOtherType... Same(other MyOtherType)
type Comparator interface {
Same(Camparator) bool // or Same(interface{}) bool
}
myType = new(MyType)
_, ok := reflect.ValueOf(myType).Interface().(Comparator) // ok - false
myOtherType = new(myOtherType)
_, ok := reflect.ValueOf(myOtherType).Interface().(Comparator) // ok - false

The types do not satisfy the Comparator interface. The types have a Same method, but those methods do not have argument type Comparator. The argument types must match to satisfy an interface.
Change the the methods and interface to take the same argument type. Use a type assertion to check that receiver and argument have the same type and to get argument as the receiver's type.
type Comparator interface {
Same(interface{}) bool
}
func (mt MyType) Same(other interface{}) bool {
mtOther, ok := other.(MyType)
if !ok {
return false
}
return return mt.MyField == mtOther.MyField
}
Use the following to compare two values:
func same(a, b interface{}) bool {
c, ok := a.(Comparator)
if !ok {
return false
}
return c.Same(b)
}
If the types the application works with have the Compare method, then there's no need to declare the Comparator interface or use the same function in the previous snippet of code. For example, the Comparator interface is not required for the following:
var mt MyType
var other interface{}
eq := mt.Same(other)

Related

Check if ast.Expr Implements Interface in Go

Is there any way we can check if any ast.Expr is implementing interface like fmt.Stringer?
I found this function types.Implements() can be used here but, I am not sure how I can create types.Interface out of an existing interface type, like fmt.Stringer, which is required for types.Implements() function.
I am looking for a function implementation like this:
func isStringer(ti *types.Info, obj ast.Expr) bool {
panic("not implemented")
}
Workaround I am using currently:
func isStringer(ti *types.Info, obj ast.Expr) bool {
t := ti.TypeOf(obj).(*types.Named)
for i := 0; i < t.NumMethods(); i++ {
if t.Method(i).Type().(*types.Signature).String() == "func() string" {
return true
}
}
return false
}
The usual way I check if an interface is implemented is by using a long form type assertion
Ex:
func isStringer(obj ast.Expr) bool {
_, ok := obj.(fmt.Stringer)
return ok
}
What's going on here is that when we provide a second variable to the type assertion (usually named ok by convention), go will not panic if the type cannot be cast, instead it will set ok = false.
We can then simply return the value of ok and be assured that if ok == true the obj implements stringer and if ok == false it does not.
If we want to use the methods provided by the stringer interface, we can return the cast variable as well:
func isStringer(obj ast.Expr) (fmt.Stringer, bool) {
return obj.(fmt.Stringer)
}

How are interface types handled between functions?

I have some questions about interfaces, especially when these interfaces are passed between functions.
I understand that interfaces are satisfied implicitly, meaning the following code is valid:
type itemX struct {}
func (x *itemX) Do() string {
return "itemX"
}
type Itf interface {
Do() string
}
func test(i Itf) string {
return i.Do()
}
func main() {
x := new(itemX)
str := test(x) // valid, since x implicitly satisfies Itf
}
However, it is not so clear what happens or what the type contract is like when I start passing interfaces between functions. An example:
// itemX, Itf, and test have the same declaration as the above snippet
func returnsItf(i Itf) Itf {
return i
}
func returnsTypeAssertedX(i Itf) Itf {
return i.(*itemX)
}
func takeItf(i Itf) {}
func takeX(x *itemX) {}
func main() {
x := new(itemX)
var i Itf = x
a := returnsItf(i) // returns type Itf
_ = takeItf(a) // no error
b := returnsTypeAssertedX(i)
_ = takeItf(b) // no error, since *itemX implements Itf
_ = takeX(b) // error, cannot use b (type Itf as *itemX)
}
There seems to be some hidden behavior when an interface is passed out as a function return. If the return is *itemX and type is Itf, the return is transformed into Itf before the function frame is terminated.
So, this implicit check (concrete -> interface if type is interface) is done twice per function call:
at the start of each function call,
and at the end.
Is my understanding of this implicit transformation correct?
An interface is a data type that has two members: The type of the underlying object, and a pointer to that object. So, wen you use a non-interface type in a context that needs an interface, the compiler constructs an interface type from that value, and uses that.
func returnsTypeAssertedX(i Itf) Itf {
return i.(*itemX)
}
In the above function, it first type-asserts that the passed in argument is of the required type, and then converts the underlying value of the argument back to an interface.
b := returnsTypeAssertedX(i)
_ = takeX(b)
The above will not work, because b is an interface{}, and takeX requires an *itemX. However, this would work:
takeX(b.(*itemX))

Go interface to enforce same argument type between methods (but can be any type)

The title is confusing, I'm sure, but it's hard to describe what I mean.
I want to create a Go interface that has two methods; the first one returns a value, and the second one accepts a value. I want to ensure that method 1 returns the same type as method 2 accepts, without specifying what the type is (other than it being a struct). For example:
type MyInterface interface {
Method1() MyType
Method2(MyType) error
}
Where MyType can be any type (of struct), as long as it's the same in both Method 1 and Method 2.
Is there any way to do this in Go?
EDIT:
Based on #iLoveReflection's answer, I've tried the following:
package main
type MyInterface interface {
GetType() interface{}
UseType(input interface{})
}
type MyImplementation struct{}
type MyType struct {
}
func (i MyImplementation) GetType() MyType {
return MyType{}
}
func (i MyImplementation) UseType(input MyType) {
return
}
func test(input MyInterface) {
return
}
func assertArgAndResult() {
var v MyImplementation
v.UseType(v.GetType())
}
func main() {
test(MyImplementation{})
}
So basically, I'm specifying an interface (MyInterface), and I want to ensure that a given implementation of that interface (MyImplementation, which would be created by the user of my package) meets the requirement stated in the original post.
assertArgAndResult() is working as expected, and ensures that MyImplementation meets the requirements. However, I get a compile error in the main() function:
cannot use MyImplementation literal (type MyImplementation) as type MyInterface in argument to test:
MyImplementation does not implement MyInterface (wrong type for GetType method)
have GetType() MyType
want GetType() interface {}
Add the following function to a package to ensure that the input and output types match at compile time:
func assertArgAndResult() {
var v MyInterface
v.Method2(v.Method1())
}
This function will not be included in the executable as long as the function is not called.
There is no compile time check that will ensure that MyType is a struct type as specified in the question.
The reflect package can be used to check type types completely.
// checkItf returns true of the interface value pointed to by
// pi has Method1 with some return type T and Method2 with
// argument type T.
func checkItf(pi interface{}) bool {
t := reflect.TypeOf(pi)
if t.Kind() != reflect.Ptr {
return false // or handle as error
}
t = t.Elem()
if t.Kind() != reflect.Interface {
return false // or handle as error
}
m1, ok := t.MethodByName("Method1")
// Method1 should have no outputs and one input.
if !ok || m1.Type.NumIn() != 0 || m1.Type.NumOut() != 1 {
return false
}
// Method2 should have one input and one output.
m2, ok := t.MethodByName("Method2")
if !ok || m2.Type.NumIn() != 1 || m2.Type.NumOut() != 1 {
return false
}
e := reflect.TypeOf((*error)(nil)).Elem()
s := m1.Type.Out(0)
// The type must be a struct and
// the input type of Method2 must be the same as the output of Method1 and
// Method2 must return error.
return s.Kind() == reflect.Struct &&
m2.Type.In(0) == s &&
m2.Type.Out(0) == e
}
Call it like this:
func init() {
if !checkItf((*MyInterface)(nil)) {
panic("mismatched argument and return time son MyInterface")
}
}

Creating array of struct dynamically in golang

I try to create a generic function that accepts any struct value and create a array of that struct type. Here is the code I tried. But I get the error "t is not a type". How can I implement this.
type RegAppDB struct {
nm string
data []interface{}
}
func CreateRegTable(tbl string, rec interface{}) RegAppDB {
t := reflect.TypeOf(rec)
fmt.Println(t)
return RegAppDB{"log", []t}
}
Go does not support generics, and any attempt to do something like that is not going to work out well. In your specific case, there are a couple of key problems:
You cannot use a variable as a type. Go is compile-time static typed, so anything that gets type information at runtime (i.e. reflect.TypeOf) happens too late to use the way you're trying to do it.
Equally important, your struct's field is of type []interface{}, which means the only type you can use for that field is []interface{}. []string, for example, is a different type, and cannot be assigned to that field.
I took another route. Need some beautification. But this works. So now data is an array of interface and from calling function I pass pointer to structure variables to Save function.
type RegAppDB struct {
nm string
data []interface{}
cnt int
}
// CreateRegTable creates a data structure to hold the regression result
func CreateRegTable(tbl string) *RegAppDB {
return &RegAppDB{tbl, make([]interface{}, 20), 0}
}
// Save implements saving a record Regression application DB
func (rga *RegAppDB) Save(rec interface{}) error {
rga.data[rga.cnt] = rec
rga.cnt++
return nil
}
// Show implements showing the regression table
func (rga *RegAppDB) Show() error {
fmt.Println(rga.cnt)
for i := 0; i <= rga.cnt; i++ {
fmt.Println(rga.data[i])
}
return nil
}
// Compare compares two regression table for equality
func (rga *RegAppDB) Compare(rgt *RegAppDB) bool {
return reflect.DeepEqual(rga, rgt)
}
It cannot be done for a generic type. If there are a fixed number of possible types, then you can do something like the following:
type RegAppDB struct {
nm string
data interface{}
}
func CreateRegTable(rec interface{}) RegAppDB {
switch rec.(type) {
case int:
return &RegAppDB{"log", []int{}}
case string:
return &RegAppDB{"log", []string{}}
}
return nil
}
Note: Your data in RegAppDB should be of type interface{} since []int implements interface{} but not []interface{}

Accept function in argument with empty interface return type

I would like to understand why the code snippet below does not compile. What is the Go way of accepting a function as a function argument that may have any return type?
package main
func main() {
test(a) // Error: cannot use a (type func() string) as type func() interface {} in argument to test
test(b) // Error: cannot use b (type func() int) as type func() interface {} in argument to test
}
func a() string {
return "hello"
}
func b() int {
return 1
}
func test(x func() interface{}) {
// some code...
v := x()
// some more code....
}
Play: https://play.golang.org/p/CqbuEZGy12
My solution based on Volker's answer:
package main
import (
"fmt"
)
func main() {
// Wrap function a and b with an anonymous function
// that has an empty interface return type. With this
// anonymous function, the call signature of test
// can be satisfied without needing to modify the return
// type of function a and b.
test(func() interface{} {
return a()
})
test(func() interface{} {
return b()
})
}
func a() string {
return "hello"
}
func b() int {
return 1
}
func test(x func() interface{}) {
v := x()
fmt.Println(v)
}
Play: https://play.golang.org/p/waOGBZZwN7
You tripped over a very common misconception for Go newcomers: The empty interface interface{} does not mean "any type". Really, it does not. Go is statically typed. The empty interface interface {} is an actual (strongly typed type) like e.g. string or struct{Foo int} or interface{Explode() bool}.
That means if something has the type interface{} it has that type and not "any type".
Your function
func test(x func() interface{})
takes one parameter. This parameter is a (parameterless function) which returns a specific type, the type interface{}. You can pass any function to test which matches this signature: "No parameters and return interface{}". None of your functions a and b match this signature.
As said above: interface {} is not a magical abbreviation for "whatever",it is a distinct static type.
You have to change e.g. a to:
func a() interface{} {
return "hello"
}
Now this might look strange as you return a string which is not of type interface{}. This works because any type is assignable to variables of type interface{} (as every type has at least no methods :-).
As the Go specification states:
A function type denotes the set of all functions with the same parameter and result types
In your case, your result types differ (string vs interface{})
To be able to receive a function with any kind of result type, test would have to be defined as:
func text(x interface{}) { ... }
and then you will have to use reflect package to call the function stored in x.
Edit
Such a test function would look like this:
func test(x interface{}) {
v := reflect.ValueOf(x)
if v.Kind() != reflect.Func {
panic("Test requires a function")
}
t := v.Type()
if t.NumIn() != 0 && t.NumOut() != 1 {
panic("Function type must have no input parameters and a single return value")
}
values := v.Call(nil)
val := values[0].Interface()
// some more code..
}
Playground: https://play.golang.org/p/trC2lOSLNE

Resources