A library is providing me a series of types like this:
type T1 struct {
n int
}
type T2 struct {
n int
}
type T3 struct {
n int
}
there is a marker interface like this
type S interface {
isS()
}
func (T1) isS() {}
func (T2) isS() {}
func (T3) isS() {}
I am trying to write a function:
func getN(s S) int {
return s.n
}
Obviously, that won’t compile, and it shouldn’t.
What I am doing now is
func getN(s S) int {
if t1, ok := s.(T1); ok {
return t1
}
if t2, ok := s.(T2); ok {
return t2
}
...
}
That works, but it unbearably awful. The library adds new T structures fairly often and it’s a disastrous violation of open/closed. Any tolerable language has a facility for this kind of situation; what is Golang’s?
Create a method on the interface that returns the type you are looking for. That will get it to compile correctly.
type S interface {
GetN()
}
func (T1) GetN() int {
// impl
}
func (T2) GetN() int {
// impl
}
func (T3) GetN() int {
// impl
}
then if you still need your interesting function that takes an interface, you can do this:
func getN(s S) int {
return s.GetN()
}
Related
I am new to learning Go and have a question around defining an argument that could be one of two types.
Take the code:
type Thing struct {
a int
b int
c string
d string
}
type OtherThing struct {
e int
f int
c string
d string
}
func doSomething(t Thing/OtherThing) error {
fmt.println(t.d)
return nil
}
As the structs have no functions I cannot write an interface for them at present.
So what is the Go idiomatic thing to do here? Is it just to bolt on a random function to the structs and write an interface or something else?
Thanks for the help...
Declare a interface with the common functionality for the two types. Use the interface type as the argument type.
// Der gets d values.
type Der interface {
D() string
}
type Thing struct {
a int
b int
c string
d string
}
func (t Thing) D() string { return t.d }
type OtherThing struct {
e int
f int
c string
d string
}
func (t OtherThing) D() string { return t.d }
func doSomething(t Der) error {
fmt.Println(t.D())
return nil
}
You can give two structs some shared functionality by composing them both from a base struct:
package main
import (
"fmt"
)
// Der gets d values.
type Der interface {
D() string
}
type DBase struct {
d string
}
func (t DBase) D() string { return t.d }
type Thing struct {
DBase
a int
b int
c string
}
type OtherThing struct {
DBase
e int
f int
c string
}
func doSomething(t Der) error {
fmt.Println(t.D())
return nil
}
func main() {
doSomething(Thing{DBase: DBase{"hello"}})
doSomething(OtherThing{DBase: DBase{"world"}})
}
DBase provides the field (d) and satisfies the Der interface the same way for both Thing and OtherThing. It does make the struct literal a little longer to define.
You can use an interface{} argument and the reflect package to access the common field. Many people will say that this approach is not idiomatic.
func doSomething(t interface{}) error {
d := reflect.ValueOf(t).FieldByName("d").String()
fmt.Println(d)
return nil
}
Try an example on the playground.
I'm trying to use builder patterns (borrowed from Java) to allow structs to implement interfaces. For example, I would ideally like this code pattern:
package main
import "fmt"
type Oner interface {
One() int
}
type Twoer interface {
Two() int
}
func main() {
s := NewObject().
WithOne(1).
Build()
_, ok := s.(Oner)
fmt.Println(ok) // Prints true
_, ok = s.(Twoer)
fmt.Println(ok) // Prints false
t := NewObject().
WithOne(1).
WithTwo(2).
Build()
_, ok = t.(Oner)
fmt.Println(ok) // Prints true
_, ok = t.(Twoer)
fmt.Println(ok) // Prints true
}
As you could see, the definition of the builder determines what interfaces s and t implement.
How would one write the function definition of the builder NewObject() so the Build() method returns a struct which can (possibly) implement a Oner and Twoer?
Edit:
Here's some clarification on how it's going to be used. I'm constructing a library barring certain structs from being passed into functions if they violate the type safety. For example:
type Oner interface {
One() int
}
type OneAndTwoer interface {
Oner
Two() int
}
type Library interface {
DoSomethingWithOner(Oner)
DoSomethingWithOneAndTwoer(Twoer)
}
Though we can define a function which always constructs a OneAndTwoer, my constraints are whenever we construct a OneAndTwoer, this takes a lot longer time than just constructing a Oner
func NewOneAndTwoer() OneAndTwoer {
// Do some really really complicated logic which takes a lot of time
}
func NewOner() Oner {
// Do simple logic
}
You could imagine how if we have a Threer, Fourer, etc, this becomes extremely unwieldly, and we have to construct constructors for all possible permutations of attributes.
This is where builder patterns come in handy. Assuming the calculations for One, Two, etc are independent of each other, we can pick and choose which interface we want to create.
Here is a way to do it, though it feels very clunky.
package main
import (
"fmt"
)
type FieldOner interface {
FieldOne() int
}
type FieldTwoer interface {
FieldTwo() int
}
Set up structs One and Two implementing FieldOner and FieldTwoer respectively.
type One struct {
one int
}
func (f One) FieldOne() int {
return f.one
}
type Two struct {
two int
}
func (f Two) FieldTwo() int {
return f.two
}
Create the FieldBuilder which can store both values and whether it has been given each value, plus WithFieldOne and WithFieldTwo.
type FieldBuilder struct {
one int
has_one bool
two int
has_two bool
}
func NewObject() FieldBuilder {
return FieldBuilder{ has_one: false, has_two: false }
}
func (f FieldBuilder) WithFieldOne(one int) FieldBuilder {
f.one = one
f.has_one = true
return f
}
func (f FieldBuilder) WithFieldTwo(two int) FieldBuilder {
f.two = two
f.has_two = true
return f
}
Build might return One, Two, or a combination of One and Two. Since it can return multiple things which have nothing in common between them (a red flag) it returns an interface{}.
func (f FieldBuilder) Build() interface{} {
switch {
case f.has_one && f.has_two:
return struct {
One
Two
}{
One{one: f.one}, Two{two: f.two},
}
case f.has_one:
return One{ one: f.one }
case f.has_two:
return Two{ two: f.two }
}
panic("Should never be here")
}
Because Build returns an interface{} it's necessary to typecast the result in order to actually use it possibly defeating the whole point of the exercise.
func main() {
s := NewObject().
WithFieldOne(1).
Build()
s1, ok := s.(FieldOner)
fmt.Println(s1.FieldOne())
_, ok = s.(FieldTwoer)
fmt.Println(ok) // Prints false
t := NewObject().
WithFieldOne(1).
WithFieldTwo(2).
Build()
t1, ok := t.(FieldOner)
fmt.Println(t1.FieldOne())
t2, ok := t.(FieldTwoer)
fmt.Println(t2.FieldTwo())
}
This does not scale particularly well. Two interfaces require three cases. Three will require six. Four will require ten. Five will need fifteen...
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 been reading over the go-lang interface doc ; however it is still not clear to me if it is possible to achieve what I'd like
type A struct {
ID SomeSpecialType
}
type B struct {
ID SomeSpecialType
}
func (a A) IDHexString() string {
return a.ID.Hex()
}
func (b B) IDHexString() string {
return b.ID.Hex()
}
This will work fine; however I'd prefer some idiomatic way to apply the common method to both types and only define it once. Something Like:
type A struct {
ID SomeSpecialType
}
type B struct {
ID SomeSpecialType
}
func (SPECIFY_TYPE_A_AND_B_HERE) IDHexString() string {
return A_or_B.ID.Hex()
}
Essentialy you can't like you're used to, but what you can do is anonymously inherit a super-struct (sorry it's not the legal word :P):
type A struct {
}
type B struct {
A // Anonymous
}
func (A a) IDHexString() string {
}
B will now be able to implement the IDHexString method.
This is like in many other languages kind of the same as:
class B extends A { ... }
For example, using composition,
package main
import "fmt"
type ID struct{}
func (id ID) Hex() string { return "ID.Hex" }
func (id ID) IDHexString() string {
return id.Hex()
}
type A struct {
ID
}
type B struct {
ID
}
func main() {
var (
a A
b B
)
fmt.Println(a.IDHexString())
fmt.Println(b.IDHexString())
}
Output:
ID.Hex
ID.Hex
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.