How do I check if a outer type is a type of inner type? - go

If I have different forms of user structs being passed around my application is there a way to check if that embedded struct is a type of the outer struct?
type (
user struct {
name string
email string
}
admin struct {
user
level string
}
)

Depending on you need, you have two main methods: reflect.TypeOf, and the type swtich.
You will use the first to compare the type of an interface with another one. Example:
if reflect.TypeOf(a) == reflect.TypeOf(b) {
doSomething()
}
You will use the second to do a particular action given the type of an interface. Example:
switch a.(type) {
case User:
doSomething()
case Admin:
doSomeOtherThing()
}

Related

Golang: How to embed interface with different type parameters?

The code gives me error: DB redeclared.
Is there any idiomatic way to solve it? Or any work-around?
TIA
type a struct {
DB[int64]
DB[string]
}
type b interface {
DB[int64]
DB[string]
}
type DB[T any] interface {
GetList(query string) ([]T, error)
}
You can't embed the same interface, even with different type parameters. Regardless of how it is instantiated, you are trying to promote into the b interface two methods with the same name GetList and different signatures — given by the different instantiations of DB.
The situation is similar, although not technically the same, for embedding into a struct. In structs, the name of the embedded field is the name of the type — DB —, and a struct can't have two non-blank fields with the same name.
About how to solve this issue, it depends what you want to accomplish.
If you want to convey that "a implements DB with either type parameter" you can embed DB[T] and make a itself generic, and restrict a's type parameters:
type a[T int64 | string] struct {
DB[T]
}
// illustrative implementation of the DB[T] interface
// if you embed DB[T] you likely won't use `a` itself as receiver
func (r *a[T]) GetList(query string) ([]T, error) {
// also generic method
}
This is okay because DB's type parameter is constrained to any, and a's type parameter is more restrictive. This allows you to use a in other generic methods, or choose a specific type upon instantiation, but the implementation of GetList has to be parametrized too.
Otherwise if you need a to have separated methods that return int64 or string, you must give it different names.
Finally, you can embed instances of DB into two interfaces with different names, and then embed those into a instead.
type a struct {
DBStr
DBInt
}
type DBStr interface {
DB[string]
}
type DBInt interface {
DB[int64]
}
This way though the top-level selector isn't available because the method names are still the same. The program compiles, but you'll have to explicitly choose which field to call the method on:
myA := a{ /* init the two fields */ }
res, err = myA.DBStr.GetList(query)
// res is type []string
// or
res, err = myA.DBInt.GetList(query)
// res is type []int64

Does type definition help assign restricted values?

In the below struct type:
type Employee struct {
Name string `json:"name"`
JobTitle JobTitleType `json:"jobtitle"`
}
member JobTitle should be ensured to have restricted(specific) values( of string type).
type JobTitleType string
const(
GradeATitle JobTitleType = "Clerk"
GradeBTitle JobTitleType = "Manager"
)
Does type definition(JobTitleType) help assign restricted values to member JobTitle?
No. You can assign any value to JobTitle:
e.JobTitle=JobTitleType("bogus")
The JobTitleType is based on string, so all string values can be converted to it.
You can use getter/setters to enforce runtime validation.
No, it will not restrict the values, any value that has type JobTitleType can be assigned to JobTitle. Currently, there is no enum type in Go. For restricting values you will probably need to write your own logic.
No, you should use it in the validation logic. For example, https://github.com/go-playground/validator has oneOf operator for validation.
Go don't have enum type, but you can do something like this
package main
import (
"fmt"
)
var JobTitleTypes = newJobTitleTypeRegistry()
func newJobTitleTypeRegistry() *jobTitleTypeRegistry{
return &jobTitleTypeRegistry{
GradeATitle : "Clerk",
GradeBTitle : "Manager",
}
}
type jobTitleTypeRegistrystruct {
GradeATitle string
GradeBTitle string
}
func main() {
fmt.Println(JobTitleTypes.GradeATitle)
}

How to pass different types as struct{} to function in GoLang?

I want to write a function that takes different struct-types as 1 parameter. Also, I have to be sure, that in these structs is an Id field. So I want a function like this:
MyFunction(object *struct{ Id int })
I tried it with passing the struct as a *struct{ Id int } and an interface{} parameter.
For example, I have these 2 struct-types:
type TableOne struct {
Id int
name string
date string
}
type TableTwo struct {
Id int
address string
athome bool
}
To save them in the database (using reflection) I have the following function:
func SaveMyTables(tablename string, obj *struct{ Id int }) {
// ... Some code here
if obj.Id != 0 {
// ... Some code here
}
// ... Some code here
}
I call the function like this:
obj := &TableTwo{
Id: 5
address: "some address"
athome: false
}
myPackage.Save("addresses", obj).
But I get this error:
cannot use obj (type *mytables.TableTwo) as type *struct { Id int } in argument to myPackage.Save
I want to write a function that takes different struct-types as 1 parameter. Also, I have to get sure, that in these struct is an Id field.
As of the current version of Go, you cannot do this. The only way Go supports passing multiple argument types to a single parameter is through the use of interfaces, and interfaces can only specify method sets, not fields.
(Go 2 plans to add generics, and this may be possible then. However, there's no concrete timeline for when that will be available.)

Subtypes Supertypes in go

Coming from OOP paradigms and porting a code from an OOP language, I come across a problem now which is solved in OOP via abstraction so I'm wondering how can I approach the following problem in Go which follows composition instead of inheritance.
In this scenario my ValueObjects (DTO, POJO etc.) are composed of other ValueObjects. I'm populating them through web service calls that returns json so basically my functions/method calls are common for all types and subtypes.
My super type EntityVO
type EntityVO struct {
EntityName string
EntityType string
PublicationId string
Version string
}
A subtype 1 composed with EntityVO
type ArticleVO struct {
EntityVO
ContentSize string
Created string
}
subtype 2 composed with EntityVO with it's own unique set of fields
type CollectionVO struct {
EntityVO
ProductId string
Position string
}
I'm calling web services to retrieve data and populate these VOs.
Earlier I had one function to call the web service and populate the data but now I'm duplicating the code for each VO.
type Article struct{}
func (a *Article) RequestList(articleVO *valueObject.ArticleVO) (*valueObject.ArticleVO, error) {
// some code
}
Duplicating the same code but changing the signature.
type Collection struct{}
func (c * Collection) RequestList(collectionVO *valueObject.CollectionVO) (*valueObject.ArticleVO, error) {
// some code - duplicate same as above except method signature
}
and I've several entities and just because my VO's are different I'm forced to duplicate the code and cater to each type of VO I've. In OOP sub types can be passed to a function accepting super types but not in go, so wondering how it should be done so I don't end up duplicated code that's different in signature only?
Any advice for a better approach in this kind of scenario?
This is where golang interfaces can shine.
It's worth noting, however, that it's difficult to write subclass/inheritance code in golang. We'd prefer thinking of it as composition.
type EntityVO interface {
GetName() string
SetName(string) error
GetType() string
...
}
type EntityVOImpl struct {
EntityName string
EntityType string
PublicationId string
Version string
}
func (e EntityVOImpl) GetName() string {
return e.EntityName
}
...
type ArticleVOImpl struct {
EntityVOImpl
ContentSize string
Created string
}
type CollectionVOImpl struct {
EntityVO
ProductId string
Position string
}
// CODE
func (e *Entity) RequestList(entityVO valueObject.EntityVO) (valueObject.EntityVO, error) {
// some code
}
In addition, as long as your interface files are shared, I don't think there should by any problem sending/marshalling/unmarshalling the structs over the wire.
The second parameter of json.Unmarshal is a "universal" interface{} type. I think similar approach is applicable to your case.
Define data type for storing web service properties which may differ for each entity, e.g.
type ServiceDescriptor struct {
URI string
//other field/properties...
}
Function for populating the entity may look like
func RequestList(desc *ServiceDescriptor, v interface{}) error {
//Retrieve json data from web service
//some code
return json.Unmarshal(data, v)
}
You can call the function to populate different type of entities, e.g.
desc := &ServiceDescriptor{}
article := ArticleVO{}
desc.URI = "article.uri"
//...
//You must pass pointer to entity for 2nd param
RequestList(desc, &article)
collection := CollectionVO{}
desc.URI = "collection.uri"
//...
//You must pass pointer to entity for 2nd param
RequestList(desc, &collection)

Defining a MongoDB Schema/Collection in mgo

I want to use mgo to create/save a MongoDB collection. But I would like to define it more extensively (for e.g to mention that one of the attribute is mandatory, another one is of an enum type and has a default value).
I have defined the struct like this, but don't know how to describe the constraints on it.
type Company struct {
Name string `json:"name" bson:"name"` // --> I WANT THIS TO BE MANDATORY
CompanyType string `json:"companyType" bson:"companyType"` // -->I WANT THIS TO BE AN ENUM
}
Is this possible to do in mgo, like how we can do it in MongooseJS?
mgo isn't an ORM or a validation tool. mgo is only an interface to MongoDB.
It's not bad to do validation all by yourself.
type CompanyType int
const (
CompanyA CompanyType = iota // this is the default
CompanyB CompanyType
CompanyC CompanyType
)
type Company struct {
Name string
CompanyType string
}
func (c Company) Valid() bool {
if c.Name == "" {
return false
}
// If it's a user input, you'd want to validate CompanyType's underlying
// integer isn't out of the enum's range.
if c.CompanyType < CompanyA || c.CompanyType > CompanyB {
return false
}
return true
}
Check this out for more about enums in Go.

Resources