How to enforce a type check and check if the object is implementing an interface?

Following is the piece of code which is puzzling. Question is how to make sure

        package main

import (
	"fmt"
)

type PersonAttributes struct {
	firstName string
}

type Behaviour interface {
	Run()
	Walk()
}

type Manager struct {
	mapper map[string]interface{}
}

func NewManager() Manager {
	return Manager{
		mapper: make(map[string]interface{}),
	}
}

func (m *Manager) AddToManager(d interface{}) {
	m.mapper["a"] = d

}

func NewPerson() PersonAttributes {

	return PersonAttributes{
		firstName: "Atul",
	}
}

func (s *PersonAttributes) Run() {
	fmt.Println("Running")

}

func (s *PersonAttributes) Walk() {
	fmt.Println("Walking")

}

func main() {

	obj := NewPerson()
	manager := NewManager()
	manager.AddToManager(obj)

	//This is running and is expected to run.
	//obj.Run()

	//However this is failing even tough Person has the behaviour defined
	if rt, okk := manager.mapper["a"].(Behaviour); okk {
		//Question1:Why is this block not running?
		//Question2:How can I run this block?

		rt.Run()
	}
}

https://play.golang.org/p/FOuIft2YQDk

1 Like

You added value type PersonAttributes to Manager and your methods are defined on a pointer receiver meaning there are no Behaviour methods on the value reciver. You have either to define Run and Walk on PersonAttributes (not *PersonAttributes) or use pointers:

func NewPerson() *PersonAttributes {

	return &PersonAttributes{
		firstName: "Atul",
	}
}

By the way, it is common in Go that functions with name NewSomething return pointers.

3 Likes

@acim thanks a lot. Trying to understand this in details.
Why would the return type as pointer matter here ?
Why would it matter ‘which’ object is being passed?
Why not any object which implements the functions would be successful in the type check?

1 Like

I put more comments in the post above, but still it may not be clere. So, in Go you can define methods on value or pointer receivers and it is not the same. If you add methods to pointer receiver, like you did, than you also have to check pointer against some interface, not value. And opposite, if you define methods on value receiver, than check value against the interface.
Do not mix methods, so if you have methods on pointer receiver, let all methods on this object be on the pointer and opposite.
Finally, function NewSomething in Go should return a pointer, not value, that is expected behaviour.

2 Likes

Thanks a lot @acim . Its very clear now.

1 Like

It is because NewPerson() returns PersonAttributes and not *PersonAttributes.

If you change NewPerson() to the following, it will work.

func NewPerson() *PersonAttributes {

	return &PersonAttributes{
		firstName: "Atul",
	}
}
2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.