Returning interfaces in Golang - struct

I am trying to write a method on a struct that takes in a interface type and returns that interface type but converted to the appropriate type.
type Model interface {
GetEntity()
}
type TrueFalseQuestions struct {
//some stuff
}
func (q *TrueFalseQuestions) GetEntity() {
//some stuff
}
type MultiQuestions struct {
//some stuff
}
func (q *MultiQuestions) GetEntity() {
//some stuff
}
type Manager struct {
}
func (man *Manager) GetModel(mod Model) Model {
mod.GetEntity()
return mod
}
func main() {
var man Manager
q := TrueFalseQuestions {}
q = man.GetModel(&TrueFalseQuestions {})
}
So when I call GetModel() with type TrueFalseQuestions I want to automatically return a TrueFalseQuestions type. I figured that would mean that my GetModel() method should return a Model type. That way if I pass a MultiQuestion type a MultiQuestion struct is returned.

You can't directly return a TrueFalseQuestions when the return type is Model. It will always be implicitly wrapped in a Model interface.
To get the TrueFalseQuestions back, you need to use a type-assertion. (you also need watch out for pointers vs values)
// this should be a pointer, because the interface methods all have pointer receivers
q := &TrueFalseQuestions{}
q = man.GetModel(&TrueFalseQuestions{}).(*TrueFalseQuestions)
That of course can panic if you got a MultiQuestions, so you should check the ok value, or use a type switch
switch q := man.GetModel(&TrueFalseQuestions{}).(type) {
case *TrueFalseQuestions:
// q isTrueFalseQuestions
case *MultiQuestions:
// q is MultiQuestions
default:
// unexpected type
}

You can't, however you can use type assertion on the returned value.
func main() {
var man Manager
tfq := &TrueFalseQuestions{}
q := man.GetModel(tfq)
if v, ok := q.(*TrueFalseQuestions); ok {
fmt.Println("v is true/false", v)
} else if v, ok := q.(*MultiQuestions); ok {
fmt.Println("v is mq", v)
} else {
fmt.Println("unknown", q)
}
}
playground

Related

Vala, string to enum

Is there a way to convert a string to an enum in vala:
string foo = "Enum1";
MY_ENUM theEnum = MY_ENUM.get_value_by_name(foo);
enum MY_ENUM {
Enum1,
Enum2,
Enum3
}
So in this example "theEnum" would have the value: MY_ENUM.Enum1
It is possible using the runtime type system provided by GLib's GObject library. There are EnumClass and EnumValue. These provide introspection at runtime and allow an enum to be initialised from a string.
The syntax is a bit complex at present, although it may be possible for someone to modify the Vala compiler to make it easier, but that is a significant piece of work.
An example:
void main () {
try {
MyEnum? the_enum_value;
the_enum_value = MyEnum.parse ("FIRST");
print (#"$(the_enum_value)\n");
} catch (EnumError error) {
print (#"$(error.message)\n");
}
}
errordomain EnumError {
UNKNOWN_VALUE
}
enum MyEnum {
FIRST,
SECOND,
THIRD;
public static MyEnum parse (string value) throws EnumError {
EnumValue? a;
a = ((EnumClass)typeof (MyEnum).class_ref ()).get_value_by_name ("MY_ENUM_" + value);
if (a == null) {
throw new EnumError.UNKNOWN_VALUE (#"String $(value) is not a valid value for $(typeof(MyEnum).name())");
}
return (MyEnum)a.value;
}
}

Is there a way to list methods of an object in GoLang? [duplicate]

The Golang "fmt" package has a dump method called Printf("%+v", anyStruct). I'm looking for any method to dump a struct and its methods too.
For example:
type Foo struct {
Prop string
}
func (f Foo)Bar() string {
return f.Prop
}
I want to check the existence of the Bar() method in an initialized instance of type Foo (not only properties).
Is there any good way to do this?
You can list the methods of a type using the reflect package. For example:
fooType := reflect.TypeOf(&Foo{})
for i := 0; i < fooType.NumMethod(); i++ {
method := fooType.Method(i)
fmt.Println(method.Name)
}
You can play around with this here: http://play.golang.org/p/wNuwVJM6vr
With that in mind, if you want to check whether a type implements a certain method set, you might find it easier to use interfaces and a type assertion. For instance:
func implementsBar(v interface{}) bool {
type Barer interface {
Bar() string
}
_, ok := v.(Barer)
return ok
}
...
fmt.Println("Foo implements the Bar method:", implementsBar(Foo{}))
Or if you just want what amounts to a compile time assertion that a particular type has the methods, you could simply include the following somewhere:
var _ Barer = Foo{}

Is implementing REST response in generic way general?

What I want to do is:
1. Parse model from url parameter in endpoint.(ex: media, account)
mysite.com/v1/rest/:model <- :model can be whether 'media', 'account'.
So it will look like:
mysite.com/v1/rest/media
mysite.com/v1/rest/account
2. Use 1, retrieve string and use it for getting corresponding struct.
3. Put it to the method which takes interface{}
My code looks like:
type Media struct {
Caption string
}
type Account struct {
Bio string
}
type AdminController struct {
TableName string
ID int64
}
func (c *AdminController) Get(n *core.Network) {
// I want to put struct to below GetModels method dynamically.
// Not explicitly like this.
total, data, err := c.GetModels(&Media{}, n)
// I want to do this
total, data, err := c.GetModels(caster("media"), n)
if err != nil {
n.Res.Error(err)
} else {
n.Res.Success(total, data)
}
}
Is it possible to implement method which takes string and return corresponding struct? Like this:
func (c *AdminController) caster(model string) interface{} {
if string == "media" {
return &Media{}
} else if string == "account" {
return &Account{}
}
return nil
}
If it's possible, is this a good way to deal with REST request (generic way) Or should I implement response methods one by one following table by table?
If I have to implement REST(4) * number_of_tables methods, it doesn't seem to be efficient. Any advice on this architectural problem will be appreciated.

Can you pass a struct fieldname in to a function in golang?

Say for example you have something like this, trying to make the example as simple as possible.
type Home struct {
Bedroom string
Bathroom string
}
How do you pass the field name, or can you, to a function?
func (this *Home) AddRoomName(fieldname, value string) {
this.fieldname = value
}
Obviously that does not work... The only way I can see to do this is to use two functions which adds a lot of extra code when the struct gets really big and has a lot of similar code.
func (this *Home) AddBedroomName(value string) {
this.Bedroom = value
}
func (this *Home) AddBathroomName(value string) {
this.Bathroom = value
}
The only way that I am aware of is to use reflection:
func (this *Home) AddRoomName(fieldname, value string) {
h := reflect.ValueOf(this).Elem()
h.FieldByName(fieldname).Set(reflect.ValueOf(value))
return
}
http://play.golang.org/p/ZvtF_05CE_
One more idea that comes to my mind is like this, not sure if it makes sense in your case though:
func Set(field *string, value string) {
*field = value
}
home := &Home{"asd", "zxc"}
fmt.Println(home)
Set(&home.Bedroom, "bedroom")
Set(&home.Bathroom, "bathroom")
fmt.Println(home)
http://play.golang.org/p/VGb69OLX-X
Use type assertions on an interface value:
package main
import "fmt"
type Test struct {
S string
I int
}
func (t *Test) setField(name string, value interface{}) {
switch name {
case "S":
t.S = value.(string)
case "I":
t.I = value.(int)
}
}
func main() {
t := &Test{"Hello", 0}
fmt.Println(t.S, t.I)
t.setField("S", "Goodbye")
t.setField("I", 1)
fmt.Println(t.S, t.I)
}

Is there a way to cast Structs for sending over a channel

In GOLANG is there an easy to way to cast structs for polymorphic behavior across channels? I'm trying to send different versions of a struct across one channel, so for example I'm going to have different types of Events, like a LoginEvent. Each one will have different amounts of data in the struct.
package main
import "fmt"
type Event struct {
EvtType EvtType
Username string
Data string
}
type LoginEvent struct {
Event
CallBackChannel chan *Event
}
type EvtType int
const (
Login EvtType = iota+1
Logout
ChatMessage
Presense
BuddyList
)
func main() {
fakeOutputChan := make(chan<- *Event)
ourSrvChannel := make(chan *Event)
lg := (LoginEvent{Event{Login,"",""} ,ourSrvChannel})
fakeOutputChan <- (*Event)(&lg)
fmt.Println("Hello, playground")
}
The idiomatic way to do is, is to use interfaces and then do a type assertion on the receiving end. Your Event struct should ideally be an interface.
type Event interface {
// Methods defining data all events share.
}
type UserEvent struct {
Name string
}
// Define methods on *UserEvent to have it qualify as Event interface.
type LoginEvent struct {
...
}
// Define methods on *LoginEvent to have it qualify as Event interface.
Then you can define your channel to accept anything that qualifies as the Event interface.
ch := make(chan Event)
The receiving end will receive the Event objects and can do a type assertion to see what
concrete type underlies it:
select {
case evt := <- ch:
if evt == nil {
return
}
switch evt.(type) {
case *LoginEvent:
case *UserEvent:
....
}
}

Resources