I have following code in Go:
type Foo struct { Id int }
type Bar struct { Id int }
func getIdsFoo(foos []Foo) {
ids = make([]int, len(foos))
// iterate and get all ids to ids array
}
func getIdsBar(bars []Bar) {
ids = make([]int, len(bars))
// iterate and get all ids to ids array
}
Is there a clever way to create a function getIds([]Idable) that can take any struct that have method GetId() implemented?
type Identifiable interface {
GetId() int
}
func GatherIds(ys []Identifiable) []int {
xs := make([]int, 0, len(ys))
for _, i := range ys {
xs = append(xs, i.GetId())
}
return xs
}
sort uses a design patter that might help you.
Create a function that works on an slice-like interface. Then create new types based off of a slice of your concrete types.
Hopefully, the code is more clear than my description. http://play.golang.org/p/TL6yxZZUWT
type IdGetter interface {
GetId(i int) int
Len() int
}
func GetIds(ig IdGetter) []int {
ids := make([]int, ig.Len())
for i := range ids {
ids[i] = ig.GetId(i)
}
return ids
}
type Foo struct{ Id int }
type Bar struct{ Id int }
type FooIdGetter []Foo
func (f FooIdGetter) GetId(i int) int {
return f[i].Id
}
func (f FooIdGetter) Len() int {
return len(f)
}
type BarIdGetter []Bar
func (b BarIdGetter) GetId(i int) int {
return b[i].Id
}
func (b BarIdGetter) Len() int {
return len(b)
}
func main() {
var f = []Foo{{5}, {6}, {7}}
var b = []Bar{{10}, {11}, {12}}
fmt.Println("foo ids:", GetIds(FooIdGetter(f)))
fmt.Println("bar ids:", GetIds(BarIdGetter(b)))
}
There is still a bit more boilerplate than is pleasant, (Go generics... someday). It's greatest advantage is that new methods do not need to be added to Foo, Bar, or any future type you may need to work with.
Related
The example below contains 2 interfaces Foo and Bar that both implement the same interface Timestamper. It also contains the type ByTimestamp that implements sort.Interface.
As shown in the function main, I would like to use the type ByTimestamp to sort both a slice of Foos and a slice of Bars. However, the code will not compile because it cannot convert foos (type []Foo) to type ByTimestamp and it cannot convert bars (type []Bar) to type ByTimestamp.
Is it possible to sort 2 slices of different interfaces that both implement the same interface with a single type that implements sort.Interface?
package main
import (
"sort"
)
type Timestamper interface {
Timestamp() int64
}
type ByTimestamp []Timestamper
func (b ByTimestamp) Len() int {
return len(b)
}
func (b ByTimestamp) Swap(i, j int) {
b[i], b[j] = b[j], b[i]
}
func (b ByTimestamp) Less(i, j int) bool {
return b[i].Timestamp() < b[j].Timestamp()
}
type Foo interface {
Timestamper
DoFoo() error
}
type Bar interface {
Timestamper
DoBar() error
}
func getFoos() (foos []Foo) {
// TODO get foos
return
}
func getBars() (bars []Bar) {
// TODO get bars
return
}
func main() {
foos := getFoos()
bars := getBars()
sort.Sort(ByTimestamp(foos))
sort.Sort(ByTimestamp(bars))
}
The Go playground
Yes, it is possible to sort different types using one sort.Interface.
But not the way you were trying to do it. Current Go specification doesn't allow converting one slice type to another. You have to convert each item.
Here's a helper function that does it using reflection:
// ByTimestamp converts a slice of Timestamper into a slice
// that can be sorted by timestamp.
func ByTimestamp(slice interface{}) sort.Interface {
value := reflect.ValueOf(slice)
length := value.Len()
b := make(byTimestamp, 0, length)
for i := 0; i < length; i++ {
b = append(b, value.Index(i).Interface().(Timestamper))
}
return b
}
See the full example here.
And, if you only have a couple of types, then it might make sense to do type-specific conversions instead.
Is it possible to generate an interface or method set of a struct at runtime with reflection?
For example:
type S struct {
a int
}
func (s *S) Fn(b int) int {
return s.a + b
}
type I interface {
Fn(a int) int
}
func main() {
var x I = &S{a: 5}
fmt.Printf("%#v\n", x.Fn)
fmt.Printf("%#v\n", reflect.TypeOf(x).Method(0))
var y I
y.Fn = x.Fn // This fails, but I want to set y.Fn at runtime.
fmt.Printf("%#v\n", reflect.TypeOf(y).Method(0))
}
https://play.golang.org/p/agH2fQ4tZ_
To clarify, I'm trying to build a middleware library so interface I contains the http handlers and I want to wrap each hander with some sort of req/response logging so I need to return a new interface I where each function in new Interface I wraps the original + some logging.
Here's how to handle this for interfaces I and J.
type I interface { Fn1(a int) int }
type J interface { Fn2(a int) int }
type Y struct { // Y implements I by calling fn
fn func(a int) int
}
func (y Y) Fn1(a int) int { return y.fn(a) }
type Z struct { // Z implements J by calling fn
fn func(a int) int
}
func (z Z) Fn2(a int) int { return y.fn(a) }
var y I = Y{fn: x.Fn}
var z J = Z{fn: x.Fn}
There's no need to use reflection.
playground example
My use case is, I need to have several structs in Go, who will have methods of same signatures and not necessarily have to have all the methods. The following code describes the requirements and also represents my current solution.
type calc struct {
fn func(a, b int) int
gn func(a string) bool
name string
}
func add(a, b int) int {
return a + b
}
func bar(foo string) bool {
// do something
}
func sub(a, b int) int {
return a - b
}
func main() {
for c := range []calc{{
fn: add,
gn: bar,
name: "addition",
}, {
fn: sub,
name: "subtraction",
}} {
fmt.Printf("%s(10, 15) returned: %d\n", c.name, c.fn(10, 15))
if c.gn != nil {
c.gn(c.name)
}
}
}
My question is how to improve this code? What's the best way to achieve this in Go? Can I achieve a better solution using interface?
Use interfaces.
type Op interface {
Name() string
Do(a, b int) int
}
type Add struct{}
func (Add) Name() string { return "add" }
func (Add) Do(a, b int) int { return a + b }
type Sub struct{}
func (Sub) Name() string { return "sub" }
func (Sub) Do(a, b int) int { return a - b }
Playground: http://play.golang.org/p/LjJt6D0hNF.
EDIT: Since you've edited your question, here is an example of how you could use asserting and interface to a broader interface for your task:
type RevOp interface {
Op
ReverseDo(a, b int) int
}
// ...
func (Add) ReverseDo(a, b int) int { return a - b }
// ...
fmt.Printf("%s(10, 15) returned: %d\n", op.Name(), op.Do(10, 15))
if op, ok := op.(RevOp); ok {
fmt.Printf("reverse of %s(10, 15) returned: %d\n", op.Name(), op.ReverseDo(10, 15))
}
Playground: http://play.golang.org/p/MQ6LlPDcEi.
I've discussed with some people in person and apparently my solution was correct. While it can be rewritten using interface, that's not necessarily an improvement.
I have multiple variables which I want to make mutually exclusive using this method
type var1WithMutex struct {
mu sync.Mutex
var1 int
}
func (v *var1) Set(value int) {
v.mu.Lock()
v.var1 = value
v.mu.Unlock()
}
func (v *var1) Get() (value int) {
v.mu.Lock()
value = v.var1
v.mu.Unlock()
return
}
Similarly there are hundreds of variable, like var1, var2, var3.... var100
How do i make all of them mutually exclusive without repeating this code?
Note that var1, var2, var3 etc are not part of an array and no way related to each other. var2 may be a int and var3 may be User{}
You could make different Mutex object for each type instead. Playground
type MutexInt struct {
sync.Mutex
v int
}
func (i *MutexInt) Get() int {
return i.v
}
func (i *MutexInt) Set(v int) {
i.v = v
}
and use it like this
func main() {
i := MutexInt{v: 0}
i.Lock()
i.Set(2)
fmt.Println(i.Get())
i.Unlock()
}
You can wrap your variables and use a shared mutex, if they all have the same interface (http://play.golang.org/p/xri2M-rtEY):
type Var interface {
Get() int
Set(n int)
}
func Sync(v Var, m *sync.RWMutex) Var {
return &syncedVar{
v: v,
m: m,
}
}
type syncedVar struct {
m *sync.RWMutex
v Var
}
func (v syncedVar) Get() int {
v.m.RLock()
defer v.m.RUnlock()
return v.v.Get()
}
func (v *syncedVar) Set(n int) {
v.m.Lock()
defer v.m.Unlock()
v.v.Set(n)
}
If your variables are primitive data types (int, float,..), use the sync.atomic package. Atomic operations do not need mutex.
I'm trying to hold a function that will return new instances of a type implementing a particular interface in a struct. Here's a stripped down example:
package main
type Adder interface {
Add(Adder)
Val() int
}
type NewAdder func() Adder
type number int
type NewHolder struct {
newFunc NewAdder
}
func (me *number)Add(it Adder) {
*me += number(it.Val())
}
func (me *number)Val() int {
return int(*me)
}
func newAdder() *number {
return (*number)(new(int))
}
func main() {
var holder NewHolder
holder.newFunc = NewAdder(newAdder)
}
When I try to compile it, it says cannot convert newAdder (type func() *number) to type NewAdder. So what's the go-like way to accomplish my goal?
Here's a Python example of what I'm trying to do, just for reference:
class NewStuffMaker(object):
def __init__(self, new):
self.new = new
def make_new():
return []
obj = NewStuffMaker(make_new)
new_lst = obj.new()
Ideally, I'd like to be able to hold a bunch of these functions (or structs containing the functions and some other data) in a slice. Is that an unreasonable thing to do?
package main
type Adder interface {
Add(Adder)
Val() int
}
type FuncAdder func() Adder
type Holder struct {
FuncAdder
SomeOtherData string
}
type number int
func (n *number) Add(a Adder) {
*n += number(a.Val())
}
func (n *number) Val() int {
return int(*n)
}
func NumberAdder() Adder {
return Adder(new(number))
}
func main() {
var holders []Holder
var holder Holder
holder.FuncAdder = NumberAdder
holder.SomeOtherData = "SomeOtherData"
holders = append(holders, holder)
}