Can I generically specifiy a Method for a Go-Lang Struct? - go

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

Related

Golang: How to use same the method for different structures

How can I apply the same logic to different structures?
For example, update a struct's field.
I want to share the same UpdateName logic for both struct A and B
A and B are from different packages.
// model/A.go
type A struct {
name string
total int64
date time.Time
}
// model/B.go
type B struct {
name string
price float64
total int64
date time.Time
}
Hopefully combine duplicated logic as one.
// service/a.go
func UpdateName(data *A) {
data.Name = "NEW"
}
// service/b.go
func UpdateName(data *B) {
data.Name = "NEW"
}
I'd like to use an interface for decoupling.
Furthermore, How can I parse interface as a parameter.
type DataSetter() interface {
SetName(name string)
SetTotal(total int64)
}
Thanks for helping me with this basic question.
For simple value assignments like you showed, it is often better to simply expose the field:
type A struct {
Name string
...
}
...
func f(a *A) {
a.Name="x"
}
You might consider embedding a common struct:
type Common struct {
Name string
}
func (c *Common) SetName(s string) {
c.Name=s
}
type A struct {
Common
...
}
type B struct {
Common
...
}
func f(a *A) {
a.SetName("x")
}
You can use an interface that represents the functions of the common type:
type WithName interface {
SetName(string)
}
func f(x WithName) {
x.SetName("x")
}
func g(a *A) {
f(a)
}
func h(b *B) {
f(b)
}
But you wouldn't want to do this for just SetName.

How to check if an attribute exists in an object's dynamic struct

I'm confused about how to check if an attribute exists in an object's dynamic struct. I.e. if we have the following structs:
type Animal struct {
Name string
Origin string
}
type Bird struct {
Animal
Speed float32
CanFly bool
}
type Bear struct {
Animal
Lazy bool
}
And now I have a function using Animal as a parameter:
func checkAminalSpeed (a Animal){
// if the struct of current animal doesn't have the Speed attribute
// print ("I don't have a speed")
//otherwise, return the speed of this animal
}
This function is trying to check the varible's runtime type to choose action.
I'd like to know in this case, how to write this checkAminalSpeed function? Thanks!
Go does not support inheritance, but perhaps you'll find the following approach tolerable.
Use an interface to define the Animal's behaviour:
type Animal interface {
GetName() string
GetOrigin() string
GetSpeed() float32
}
Use a "base" type that will contain common fields and also implement the behaviour:
type AnimalBase struct {
Name string
Origin string
}
func (a AnimalBase) GetName() string { return a.Name }
func (a AnimalBase) GetOrigin() string { return a.Origin }
func (a AnimalBase) GetSpeed() float32 { return -1 }
Embed the "base" type and override any behaviour you need to:
type Bird struct {
AnimalBase
Speed float32
CanFly bool
}
func (b Bird) GetSpeed() float32 { return b.Speed }
And then...
func checkAminalSpeed(a Animal) {
if speed := a.GetSpeed(); speed == -1 {
fmt.Println("I don't have speed")
} else {
fmt.Println(speed)
}
}
https://play.golang.org/p/KIjfC7Rdyls
mkopriva is right. Go does not support inheritance, you can use reflect and interface{} also
ps: reflect cost more time than interface
package main
import (
"fmt"
"reflect"
)
type Animal struct {
Name string
Origin string
}
type Bird struct {
Animal
Speed float32
CanFly bool
}
type Bear struct {
Animal
Lazy bool
}
func checkAminalSpeed (a interface{}){
v := reflect.ValueOf(a)
if f, ok := v.Type().FieldByName("Speed"); ok{
fmt.Printf("%v\n", f)
}
}
func main() {
checkAminalSpeed(Bird{})
checkAminalSpeed(Bear{})
}

How to combine an interface and struct in golang?

package main
type A interface {
GetName() string
}
type B struct {
A
}
func (this *B) Func1() {
this.GetName()
}
type C struct {
B
}
func (this *C) GetName() string {
return "hello"
}
func main() {
var c = new(C)
c.GetName()
c.Func1()
}
https://play.golang.org/p/1X7yiQeie8F
My question:
c.Func1() will lead to:
panic: runtime error: invalid memory address or nil pointer dereference
My scenario is:
user needs to implement some basic interfaces of A, and then user can use the member function of B. I hope that complicate codes are encapsulated into the member function of B, and user just need to provide basic infos.
How to achieve this goal?
I see your code looping forever GetName calling duplicate
you can see my code
package main
import "fmt"
type A interface {
GetName() string
}
type B struct {
A
}
func (this *B) Func1() {
}
type C struct {
B
}
func (this *C) GetName() string {
return "hello"
}
func main() {
var c = new(C)
fmt.Println(c.GetName())
}
https://play.golang.org/p/PaFd-BS9sdP

How can Subtype be referenced by Supertype in Go

Go doesn't support Polymorphism.If specific types were to be passed under the umbrella of Generic types it fails to work in Go. Following piece of code throws error . What is the best way to achieve the same functionality in Go?
package main
import (
"fmt"
)
type parent struct {
parentID string
}
type child1 struct {
parent
child1ID string
}
type child2 struct {
parent
child2ID string
}
type childCollection struct {
collection []parent
}
func (c *childCollection) appendChild(p parent) {
c.collection = append(c.collection, p)
}
func main() {
c1 := new(child1)
c2 := new(child2)
c := new(childCollection)
c.appendChild(c1)
c.appendChild(c2)
}
Go Playground Link
Just because the type Child is composed of something Parent in this case. does not mean that it is that something. These are two different types so cannot be interchangeable in this way.
Now if you had an interface Parent and your child objects meet that interface then we are talking a different thing altogether.
Edit 1
Example
https://play.golang.org/p/i6fQBoL2Uk7
Edit 2
package main
import "fmt"
type parent interface {
getParentId() (string)
}
type child1 struct {
child1ID string
}
func (c child1) getParentId() (string) {
return c.child1ID
}
type child2 struct {
child2ID string
}
func (c child2) getParentId() (string) {
return c.child2ID
}
type childCollection struct {
collection []parent
}
func (c *childCollection) appendChild(p parent) {
c.collection = append(c.collection, p)
}
func main() {
c1 := child1{"1"}
c2 := child2{"2"}
c := new(childCollection)
c.appendChild(c1)
c.appendChild(c2)
fmt.Println(c)
}

Function that takes different type of struct

I wonder how the following functions lengthAA and lengthBB can be simplified to just one function. Note in those two functions it just compute the length of the array, it is just an example and can be more complicated than that. Ideally, I want only one function that serve the same purpose (in this case, len) but can take different struct as variable.
type A struct {
id string
}
type AA struct {
ids []A
}
type B struct {
id string
value bool
}
type BB struct {
ids []B
}
func lengthAA(aa AA) int {
return len(aa)
}
func lengthBB(bb BB) int {
return len(bb)
}
The Go way of doing this would be for both AA and BB to implement a common method. length would then accept an interface that contains the same function signature. Example:
package main
import (
"fmt"
)
type Lengther interface {
Length() int
}
type A struct {
id string
}
type AA struct {
ids []A
}
func (a *AA) Length() int {
return len(a.ids)
}
type B struct {
id string
value bool
}
type BB struct {
ids []B
}
func (b *BB) Length() int {
return len(b.ids)
}
func length(l Lengther) int {
return l.Length()
}
func main() {
aa := &AA{
ids: make([]A, 10),
}
bb := &BB{
ids: make([]B, 34),
}
fmt.Println(length(aa))
fmt.Println(length(bb))
}
https://play.golang.org/p/DdxP5lFcZi
1- Using two separate receiver methods length() like this working sample code (This is idiomatic Go):
package main
import "fmt"
func (v *AA) length() int {
return len(v.ids)
}
func (v *BB) length() int {
return len(v.ids)
}
func main() {
aa := AA{[]A{A{"id"}, A{"id2"}}}
fmt.Println(aa.length()) // 2
bb := BB{[]B{B{"id", true}, B{"id2", true}}}
fmt.Println(bb.length()) // 2
}
type A struct {
id string
}
type AA struct {
ids []A
}
type B struct {
id string
value bool
}
type BB struct {
ids []B
}
2- Using one length(aa interface{}) function, like this working sample code (in some use cases this is useful):
package main
import "fmt"
func length(aa interface{}) int {
switch v := aa.(type) {
case AA:
return len(v.ids)
case BB:
return len(v.ids)
}
return -1
}
func main() {
aa := AA{[]A{A{"id"}, A{"id2"}}}
fmt.Println(length(aa)) // 2
bb := BB{[]B{B{"id", true}, B{"id2", true}}}
fmt.Println(length(bb)) // 2
}
type A struct {
id string
}
type AA struct {
ids []A
}
type B struct {
id string
value bool
}
type BB struct {
ids []B
}
3- Using reflect and one length(v interface{}) function, like this working sample code (in some use cases this is useful):
package main
import "fmt"
import "reflect"
func length(v interface{}) int {
return reflect.ValueOf(v).FieldByName("ids").Len()
}
func main() {
aa := AA{[]A{A{"id"}, A{"id2"}}}
fmt.Println(length(aa)) // 2
bb := BB{[]B{B{"id", true}, B{"id2", true}}}
fmt.Println(length(bb)) // 2
}
type A struct {
id string
}
type AA struct {
ids []A
}
type B struct {
id string
value bool
}
type BB struct {
ids []B
}
output:
2
2
This code wouldn't actually compile since len(aa) would be passing a struct to len which would fail. But I think I get what you're trying to do, and the best way to do it is with the nearest thing Go has to inheritance, which is really just struct embedding.
By making an embeddable struct, and having each of your structs that have that similar feature embed it, you can reduce the line count of the code, though "simplifying" may be a bit of a stretch.
type HasIDs struct {
Ids []string
}
type AA struct {
HasIDs
OtherValues []int
}
type BB struct {
HasIDs
OtherValues []byte
}
At this point both structs AA and BB have the value Ids []string. Now you can give the HasIDs struct a method that both structs should be able to call.
func (hasIds HasIDs) length() {
return len(hasIds.Ids)
}
And call the method on either struct that embeds the struct with the method.
a1 := AA{}
aLength := a1.length()
Here is a working code sample: https://play.golang.org/p/ys_CN_L_cr

Resources