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.
Related
I am trying to define a custom type that returns a random number and use that type in a struct but I can't seem to get it right. Here is what I am doing
type genRandFunc func() int
func genRand() genRandFunc{
return func() int {
return rand.Intn(1000)
}
}
type User struct {
parseID genRand()
}
What am I doing wrong here?
Your User type definition is wrong. getRand() is a function call, not a type. Use
type User struct {
parseID genRandFunc
}
...
x:=User{parseID: getRand()}
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)
}
Foreign application API gives me a list of names in JSON format. I need modify all of those.
But I do not like to write some loop for it (especially after Python using with reflection and stuff)
Is there any method to write something like this in Go?
type MyIncredibleType struct {
Name ModifyName // ModifyName is not a type!
}
func ModifyName(input string) string {
return input + ".com"
}
The expected behavior of this is:
a := MyIncredibleType{Name: "Abracadabra"}
print(a.Name) // Abracadabra.com
This seems pretty straight forward to me, assuming I understand your question correctly:
// ModifyName func
func ModifyName(input string) string {
return fmt.Sprintf("%v.com", input)
}
If you wish to achieve this within the type itself, without modifying (mutating) the internal state:
type MyType sturct {
name string // unexported
}
// accessor func to return name
func (t MyType) Name() string {
return t.name
}
// accessor func to return modified name
func (t MyType) ModifiedName() string {
return fmt.Sprintf("%v.com", t.name)
}
If you want to modify the internal state:
type MyType struct {
name string
}
// mutator func (note the pointer for pass by reference)
func (t *MyType) ModifyName(input string) {
t.name = fmt.Sprintf("%v.com", input)
}
// accessor (note no pointer for pass by value)
func (t MyType) Name() string {
return t.name
}
This is is not possible in GO. That's not how struct works in Go.
type MyIncredibleType struct {
Name ModifyName `json:"name"` // ModifyName is not a type!
}
you can only define Built-in types for your fields of struct or you can define Composite Literal types.
Composite literals construct values for structs, arrays, slices, and
maps and create a new value each time they are evaluated. They consist
of the type of the literal followed by a brace-bound list of elements.
Each element may optionally be preceded by a corresponding key.
Try to create a method receiver of struct which you are using to parse json coming from the api to modify the name. That will let you achieve something similar to what you want.
package main
import (
"fmt"
)
type MyIncredibleType struct {
Name string `json:"name"` // ModifyName is not a type!
}
func(myIncredibleType *MyIncredibleType) ModifyName() string {
return myIncredibleType.Name+".com"
}
func main() {
a := MyIncredibleType{Name: "Abracadabra"}
name := a.ModifyName()
fmt.Printf("%s",name)
}
Playground Example
Or you can pass an interface which will wrap any struct value with name field and then use Type assertion to get the underlying value to modify the same and return the result:
package main
import (
"fmt"
)
type MyIncredibleType struct {
Name string `json:"name"` // ModifyName is not a type!
}
func ModifyName(input interface{}) string{
return input.(interface{}).(string)+".com"
}
func main() {
a := MyIncredibleType{Name: "Abracadabra"}
name := ModifyName(a.Name)
fmt.Printf("%s",name)
}
Working code on Go Playground
For more information also go through Golang method Declarations on how to create receivers.
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
Is it possible to do conditional variable type declaration like this in Golang?
if isAdmin {
var result NormalResult
} else {
var result AdminResult
}
// do something to &result
doSomething(&result)
func doSomething(interface{}) {
// something
}
The above does not work, but the ideas is that normalResult and adminResults are very similar structs and how would I go about doing this?
Thank you!
No, not in this manner. Go being statically typed, needs to know the type information at compile time.
What you could do is declare result as an interface of some type which both AdminResult and NormalResult satisfy. You can then use a type assertion at runtime to decide which type of result it is.
(You also have to declare result outside of the if blocks because Go is block scoped)
type NormalResult struct {
Value int
}
func (r NormalResult) Result() int {
return r.Value
}
type AdminResult struct {
Value int
}
func (r AdminResult) Result() int {
return r.Value
}
type Resulter interface {
Result() int
}
func main() {
isAdmin := true
var r Resulter
if isAdmin {
r = AdminResult{2}
} else {
r = NormalResult{1}
}
fmt.Println("Hello, playground", r)
}
Depending on what kind of similarities, you might have different options.
Using embedded structs
Depending on your structure, you might be able to use embedded structs. Let's say NormalResult is defined like this:
type NormalResult struct {
Name string
Value int
}
And if AdminResult shares the same properties but just adds a few more of them (like UserId), you can choose to embed NormalResult into the AdminResult like this:
type AdminResult struct {
*NormalResult
UserId int64
}
Then you can also declare methods for NormalResult which will be promoted to AdminResult as well:
func (r *NormalResult) doSomething() {
// Doing something
}
Edit
And, no, it is not possible to have conditional types in Go as you suggested. A variable can only be of one type, be it NormalResult, AdminResult or interface{}