gosuitetalk

Using base of embedded types in Go


I'm new to Go and working with a set of types generated by gowsdl based on the NetSuite SuiteTalk web service definition. It has created the following types:

type BaseRef struct {
    XMLName xml.Name `xml:"urn:core_2018_2.platform.webservices.netsuite.com BaseRef"`
    Name string `xml:"name,omitempty"`
}

type RecordRef struct {
    XMLName xml.Name `xml:"urn:core_2018_2.platform.webservices.netsuite.com   RecordRef"`
    *BaseRef
    InternalId string `xml:"internalId,attr,omitempty"`
    ExternalId string `xml:"externalId,attr,omitempty"`
    Type *RecordType `xml:"type,attr,omitempty"`
}

type GetRequest struct {
    XMLName xml.Name `xml:"urn:messages_2018_2.platform.webservices.netsuite.com GetRequest"`
    BaseRef *BaseRef `xml:"baseRef,omitempty"`
}

As I try to use these types it is unhappy in my ability to use the specific type of reference record in a GetRequest structure which is looking for a BaseRef which is what RecordRef is based on.

var partnerRecordType RecordType
partnerRecordType = RecordTypePartner
recordRef := RecordRef{
    Type:&partnerRecordType,
    InternalId:internalIdString,
}

var getRequest GetRequest
getRequest.BaseRef = &recordRef

The error I get is on the last line is:

cannot use &recordRef (type *RecordRef) as type *BaseRef in assignment

Any thoughts on how to proceed?


Solution

  • Go does not support polymorphism in this way, neither does it support inheritance in way that say C# or Java does. Embedded structs are quite literally just embedded, they do not create a classical inheritance hierarchy. They simply give the wrapping struct all of the exposed methods and fields of the embedded struct (with some subtle caveats - check out the spec)

    That said, in your example RecordRef is not related to BaseRef in terms of its type, instead it could be considered to "contain" a pointer to a BaseRef. In order for your program to compile, you will have explicitly assign the embedded BaseRef like so:

    getRequest.BaseRef = &recordRef.BaseRef
    

    As this code you are referencing has been auto generated from a WSDL, it may be a little cumbersome to update the GetRequest to provide a BaseRef like data structure in a more polymorphic, flexible fashion, but in order to do so you will need to use Go interfaces.

    You could update the GetRequest to have a method with accepts in interface type, say XmlRef which would expose getters that can derive the data you need to assign to the GetRequest

    For example

    type XmlRef interface {
      Name() string
      InternalID() string
      ExternalID() string
    }
    
    func (r *GetRequest) SetRef(ref XmlRef) {
      r.BaseRef.Name = ref.Name()
      // etc...
    }
    

    Then simply implement the interface for RecordRef and any other structs that would need to be used in this context.