moesef
moesef

Reputation: 4851

Returning interfaces in Golang

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.

Upvotes: 0

Views: 1460

Answers (2)

Mr_Pink
Mr_Pink

Reputation: 109442

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
}

Upvotes: 4

OneOfOne
OneOfOne

Reputation: 99361

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

Upvotes: 1

Related Questions