Is there a better way to achieve the inheritance in go? (In c# we use Abstract class and Interfaces to achieve similar behavior). Please refer below code to understand the problem.
I tried using interface in Go but I am unable to access the data fields of struct.
type Vehicle struct {
Id int
Name string
VehicleType VehicleTypeBase
}
type VehicleTypeBase struct {
Id int
Name string
Milage int
}
type VehicleTypeSedan struct {
VehicleTypeBase
IsABSEnabled bool
}
type VehicleTypeHatchback struct {
VehicleTypeBase
Is4WheelDriveEnabled bool
}
func main() {
var veh Vehicle
veh = Vehicle{
Id: 1,
Name: "Zeep Compass",
VehicleType: VehicleTypeSedan{
Id: 1,
Name: "Sedan",
Milage: 13,
IsABSEnabled: true,
},
}
}
// Above initialization gives error. Here, I would like to understand that how // to achieve inheritance using base class
// in Golang. Is there a way to solve this situation in Go??
The error message is:
.\main.go:40:3: cannot use VehicleTypeSedan literal (type VehicleTypeSedan) as type VehicleTypeBase in field value
Struct embedding is how go lang prefers. Composition is better than inheritance is the idea.
https://golang.org/doc/effective_go.html#embedding
You should declare an interface for Vehicle and all the Vehicles implement that interface.
This is design level problem than just fixing the error. Since its not clear exactly how you are going to use and deal with Vehicles. I will make some assumptions.
By Embedding way should embed a reusable struct inside specific structs.
type VehicleTypeGeneral struct {
Id int
Name string
Milage int
}
//Embed VehicleTypeGeneral
type VehicleTypeHatchback struct {
VehicleTypeGeneral
Is4WheelDriveEnabled bool
}
If we creates instance vh of VehicleTypeHatchback then we can access fields of VehicleTypeHatchback as well as embedded struct VehicleTypeGeneral like vh.Is4WheelDriveEnabled and vh.VehicleTypeGeneral.Name
If VehicleTypeGeneral implement interface like Vehicle interface then VehicleTypeHatchback also implements that. You can override by implementing the methods though.
I have added type check example in processSpecificVehicle function. However these things slow the execution. Instead try to use the approached mentioned in processVehicle and processAbsVehicle
Also the interfaces should not have to many methods. One or two are enough other wise it is violation of interface segregation principle. Keep the interfaces short and meaningful and design them from the prospective of consumer of interfaces.
Complete example with certain assumptions:
package main
import "fmt"
type Vehicle interface {
GetId() int
GetName() string
}
type AbsVehicle interface {
IsAbsEnabled() bool
}
type VehicleTypeGeneral struct {
Id int
Name string
Milage int
}
func (v *VehicleTypeGeneral) GetId() int{
return v.Id
}
func (v *VehicleTypeGeneral) GetName() string{
return v.Name
}
type VehicleTypeSedan struct {
VehicleTypeGeneral
IsABSEnabled bool
}
func(vs *VehicleTypeSedan) IsAbsEnabled() bool {
return vs.IsABSEnabled
}
type VehicleTypeHatchback struct {
VehicleTypeGeneral
Is4WheelDriveEnabled bool
}
func main() {
println("Hello")
var vehicle = VehicleTypeSedan{IsABSEnabled: true, VehicleTypeGeneral: VehicleTypeGeneral{Id:1001,Name:"Sedan 1", Milage:12}}
processVehicle(&vehicle)
processAbsVehicle(&vehicle)
processSpecificVehicle(&vehicle)
processSedan(&vehicle)
}
func processVehicle(vehicle Vehicle){
println(vehicle.GetId())
println(vehicle.GetName())
}
func processAbsVehicle(vehicle AbsVehicle){
println(vehicle.IsAbsEnabled())
}
func processSpecificVehicle(vehicle Vehicle){
switch v := vehicle.(type) {
case *VehicleTypeSedan:
fmt.Printf("Its a sedan %v with ABS %v ", v.GetName(), v.IsAbsEnabled())
case *VehicleTypeHatchback:
fmt.Printf("Its a VehicleTypeHatchback %v", v.GetName())
default:
fmt.Printf("Its a Vehicle")
}
}
func processSedan(vs *VehicleTypeSedan){
println("\nprocess sedan")
println(vs.VehicleTypeGeneral.Name)
println(vs.IsABSEnabled)
}
It's can work!
type Vehicle struct {
Id int
Name string
VehicleType VehicleTypeInterface
}
type VehicleTypeInterface interface{}
type VehicleTypeBase struct {
Id int
Name string
Milage int
}
type VehicleTypeSedan struct {
VehicleTypeBase
IsABSEnabled bool
}
type VehicleTypeHatchback struct {
VehicleTypeBase
Is4WheelDriveEnabled bool
}
func main() {
var veh Vehicle
veh = Vehicle{
Id: 1,
Name: "Zeep Compass",
VehicleType: VehicleTypeSedan{
VehicleTypeBase: VehicleTypeBase{
Id: 3,
Name: "Sedan",
Milage: 13,
},
IsABSEnabled: true,
},
}
fmt.Printf("%+v", veh)
}
Related
This question already has an answer here:
How can I access a struct field with generics (type T has no field or method)?
(1 answer)
Closed 4 months ago.
I am trying to create a function using Go Generics that accepts any structs that meet minimum struct criteria. Something like <T extends {name: string, age: number}> in Typescript.
Here below is my function and I am trying to find a way to make it work. I would love to be able to pass any struct that has Name string and Age int to the printNameAndAge function because that function will be using only these two fields. Is this possible? I was not able to find an example or documentation for this use case?
package main
import "fmt"
type User struct {
Name string
Age int
Height float32
}
type Car struct {
Age int
Name string
Model string
}
type NameAndAge struct {
Name string
Age int
}
func printNameAndAge[T (**missing extends or something like that**) NameAndAge](u T) {
fmt.Println(u.Name)
fmt.Println(u.Age)
}
func main() {
newUser := User{
Name: "John",
Age: 24,
Height: 186,
}
newCar := Car{
Name: "Series 3",
Age: 1,
Model: "BMW",
}
printNameAndAge(newUser)
printNameAndAge(newCar)
}
Use interfaces. Define interface with methods for common functionality. Implement those methods on each type.
package main
import "fmt"
type User struct {
Name string
Age int
Height float32
}
func (u User) getName() string { return u.Name }
func (u User) getAge() int { return u.Age }
type Car struct {
Age int
Name string
Model string
}
func (c Car) getName() string { return c.Name }
func (c Car) getAge() int { return c.Age }
func printNameAndAge(x interface {
getName() string
getAge() int
}) {
fmt.Println(x.getName())
fmt.Println(x.getAge())
}
func main() {
newUser := User{
Name: "John",
Age: 24,
Height: 186,
}
newCar := Car{
Name: "Series 3",
Age: 1,
Model: "BMW",
}
printNameAndAge(newUser)
printNameAndAge(newCar)
}
You can try embed the substructure in your types like in the example below.
However the current solution is: interfaces
But hey thd type NameAndAge can have a method. And Car can expose this method via delegation.
type NameAndAge struct {
Name string
Age int
}
func (na NameAndAge) Get()(string, int){
return na.Name, na.Age
}
type Getter interface {
Get()(string, int)
}
type Car struct {
NameAndAge
Model string
}
func Show(na NameAndAge) {
fmt.Println(na.Name, na.Age)
}
func ShowInterface(g Getter){
fmt.Println(g.Get())
}
func main() {
var c Car
c.Name = "Ford"
c.Age = 40
c.Model = "T"
Show(c.NameAndAge)
ShowInterface(c)
}
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.
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{})
}
I need to store an object that implements a specific type in an in-memory store. The type of the object being stored must satisfy an interface which is a superset of the interface implemented by the stored object.
What I'm trying to figure out is how do I access the original [interface] type when I retrieve the object from the store? The type switch from superset to subset does not seem to be possible.
Here is a sample code that will hopefully make this easier to understand.
Interface types
type Object interface {
UID() string
Name() string
Attrs() map[string]string
Parent() string
}
type Entity interface {
UID() string
Name() string
Attrs() map[string]string
}
type Node interface {
Entity
}
type SpecialNode interface {
Node
ID() int
}
You can see that Object interface is a subset of Entity interface i.e. all Objects automatically implement Entity interface, hence Entity is a superset of Object.
Sample implementations of the interfaces:
type node struct {
Node
}
type specialNode struct {
Node
id int
}
func (n specialNode) ID() int {
return n.id
}
type object struct {
uid string
name string
attrs map[string]string
parent string
}
func (e object) UID() string { return e.uid }
func (e object) Name() string { return e.name }
func (e object) Attrs() map[string]string { return e.attrs }
func (e object) Parent() string { return e.parent }
Now, here is a sample main.go:
package main
import "fmt"
func main() {
o := object{
uid: "xyz",
name: "entName",
attrs: make(map[string]string),
parent: "entParent",
}
n := node{
Node: o,
}
sn := specialNode{
Node: n,
id: 100,
}
fmt.Printf("%#v\n", sn)
}
This prints the following as expected:
main.specialNode{Node:main.node{Node:main.object{uid:"xyz", name:"entName", attrs:map[string]string{}, parent:"entParent"}}, id:100}
Now, how do I "extract" object/Object from sn? Type switching like this sn.Node.(Object) is not possible. Is there any way to accomplish this in Go?
Link to playground
You have to cast it to an interface to type cast
See Cannot type switch on non-interface value
o2:= interface{}(sn.Node.(node).Entity.(object))
var oo2 Object = o2.(Object)
fmt.Printf("%#v\n",oo2)
Say I have a struct:
type DriverData struct {
TypePath string = "Foo.Bar.DriverData"
}
I want to be able to reference TypePath without having to create an instance of the struct, something like:
typePath := DriverData.TypePath
but that's not possible in Golang.
So I was wondering - maybe there is a way to create a map, and associate the type with a string, something like:
type DriverData struct {
}
type PilotData struct {
}
type BoatmasterData struct {
}
typeMap := map[struct]string{
DriverData: "Foo.Bar.DriverData",
PilotData: "Foo.Bar.PilotData",
BoatmasterData: "Foo.Bar.BoatmasterData",
}
Question:
Is this the best approach to create static properties on a struct? Storing the static properties in a map like this?
You can define methods to give you those values:
type DriverData struct {
}
func (DriverData) Path() string {
return "Foo.Bar.DriverData"
}
type PilotData struct {
}
func (PilotData) Path() string {
return "Foo.Bar.PilotData"
}
type BoatmasterData struct {
}
func (BoatmasterData) Path() string {
return "Foo.Bar.BoatmasterData"
}
Does that do what you want?
See https://play.golang.org/p/zR7RZwMVEdf.