Last active
November 2, 2016 11:11
-
-
Save danfairs/c7839de9cc7b311bf89d4e6acb57c75e to your computer and use it in GitHub Desktop.
Where I'd use generics in scala
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Here's the simple version - first we have a conversion function, that takes a *ContentItem and converts to a *contentpb.ContentItem. | |
func ContentItemToPb(c *ContentItem) (*contentpb.ContentItem, error) { | |
if c == nil { | |
return nil, errors.New("ContentItemToPb: ContentItem was nil") | |
} | |
return &contentpb.ContentItem{ | |
Id: &contentpb.ContentId{ | |
SourceId: c.Id.SourceId, | |
SourceName: c.Id.SourceName, | |
}, | |
Content: c.Content, | |
ContentType: string(c.ContentType), | |
}, nil | |
} | |
// Now we have a version that works with slices of the same types. | |
func ContentItemsToPb(items []*ContentItem) ([]*contentpb.ContentItem, error) { | |
pbItems := make([]*contentpb.ContentItem, len(items)) | |
for i, item := range items { | |
if item == nil { | |
return nil, errors.New(fmt.Sprintf("ContentItem at position %s is nil", i)) | |
} | |
pbItem, err := ContentItemToPb(item) | |
if err != nil { | |
return errors.New(fmt.Sprintf("Error converting item at position %s: %s", i, err.Error())) | |
} | |
pbItems[i] = pbItem | |
} | |
return pbItems, nil | |
} | |
// There are a bunch of these, all the same pattern. So what I'd really like to write is something like this: | |
type mapFunc func (interface{}) (interface{}, error) | |
func mapItems(f mapFunc, inItems []interface{}, outItems[] interface{}) error { | |
for i, inItem := range(inItems) { | |
outItem, err := mapFunc(inItem) | |
if err != nil { | |
return err | |
} | |
outItems[i] = outItem | |
} | |
} | |
// This should give rise to a function like: | |
func ContentItemsToPb2(items []*ContentItem) ([]*contentpb.ContentItem, error) { | |
outPbs := make([]*contentpb.ContentItem, len(items)) | |
err := mapItems(ContentItemToPb, items, outPbs) | |
if err != nil { | |
return nil, err | |
} | |
return outPbs, nil | |
} | |
// However, this doesn't compile - the compiler complains that the ContentItemToPb function doesn't have the right signature. | |
// I can write a small wrapper for ContentItemToPb to convert the types 'manually' with type assertions, but I end up with a | |
// lot of boilerplate - actually more than just writing the original, specialised ContentItemsToPb function! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Unfortunately it's the golang way - no generics so if you want to make generic slice mapping you will have to use type assertions/convertions and interface{} which is pretty ugly (remember: interface{} says nothing).
Some people uses
go:generate
for that. See projects like: https://github.com/dshills/yaggg or http://clipperhouse.github.io/gen/