defining a custom type in Go - go

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()}

Related

Instantiate generic interface with any, struct doesn't implement it

Can someone explain, why *DataTo does not satisfy ToType[any]?
Trying to build a DTOer, that copies all values of one struct to another and also sets some explicit values (V in this case)
https://go.dev/play/p/-oobZrw5Ewe
// You can edit this code!
// Click here and start typing.
package main
import "fmt"
type DataFrom struct {
V1 int
}
type DataTo struct {
V int
}
func (m *DataTo) SetVal() {
m.V = 1
return
}
type ToType[T any] interface {
SetVal()
*T
}
type DTO[TFrom any, TTo ToType[any]] struct {
Get func(from TFrom) TTo
}
func main() {
dto := &DTO[DataFrom, *DataTo]{
Get: func(from DataFrom) *DataTo {
return &DataTo{V: from.V1 + 666}
},
}
vFrom := DataFrom{V1: 1}
vTo := dto.Get(vFrom)
fmt.Println(vTo.V)
}
Because any is a static type.
If you use it to instantiate a generic type like ToType, that generic type will expect exactly any.
Now, certain usages of the type parameter might hide this issue, for example:
type Foo[T any] struct {
Value T
}
Foo[any]{Value: 12} // ok
Normally you are able to assign whatever type to any like the above, because any is just an alias of the empty interface interface{}, and any type satisfies the empty interface.
When the type parameter is used in composite types such as *T, then instantiating with any means exactly *any. Therefore you can imagine ToType[any] as the same thing as:
type ToTypeAny interface {
SetVal()
*any
}
And then *DataTo is obviously not *any. Further details: Assign struct pointer to interface pointer
If you declare the struct as follows it will compile:
type DTO[TFrom any, TTo ToType[DataTo]] struct {
Get func(from TFrom) TTo
}
Or in a more "generic" but also more verbose way:
type DTO[TFrom any, T any, TTo ToType[T]] struct {
Get func(from TFrom) TTo
}
&DTO[DataFrom, DataTo, *DataTo]{ ... }

How should I write this function to return a pointer?

Assuming we have the following structures:
type BuyerData struct {
id int
balance float64
}
type AgentData struct {
id int
buyerData BuyerData
}
type GlobalData struct {
agents map[int]AgentData
}
if I wanted to define a "insert equivalent of Java's class method" for GlobalData to return a pointer to it's value buyerData on a given id, which would be a method with the following signature:
func (globalData *GlobalData) getBuyerData(id int) *BuyerData
What would be written inside it? I'm having troubles because it's giving all sorts of errors like cannot take the address of, invalid indirect of or does not support indexing...
This is what I currently have that does not generate any compiler exception:
func (globalData *GlobalData) getBuyerData(id int) *BuyerData {
var agents *map[int]AgentData = &(globalData.agents)
var agentData AgentData = (*agents)[id]
return &(agentData.buyerData)
}
But I, honestly, don't know what I'm doing or if this is the correct way of doing it.
Assuming you'd just like to return a pointer to the value in the map in a AgentData struct indexed by the argument of the function, you likely mean to say:
func (agentsGlobalData *AgentData) getBuyerData(id int) (*BuyerData, bool) {
buyer, has := agentsGlobalData.agents[id]
return &buyer, has
}
You might also consider storing pointers to AgentData in that map instead, making your struct:
type GlobalData struct {
agents map[int]*AgentData
}
But you haven't told us enough about your use case to recommend one or the other, perhaps.
(You say callers should be able to "write" to a BuyerData, but there are not any public fields in that struct...)
You need to say something like this:
func (globalData *GlobalData) GetBuyerData(id int) *BuyerData {
if agent, found := globalData.Agents[id]; found {
return &agent.BuyerData
}
return nil
}
See it here: https://play.golang.org/p/lwXn4D1mr3J

Static member of a struct in Golang

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.

How to make possible to return structs of different types from one function with Golang?

I have a function which queries database, then, depending on result form it, can create a struct OrderWithoutDetails or OrderWithDetails depending on the presence of details about the order.
How do I make the function to be able to return result of both types?
You can use interface{}
func queryDb() interface{}{
}
But the better will be if your 2 type of struct can have a common function, that can satisfy a common interface, it will be cleaner.
Example :
type s1 struct{
id int
name string
}
type s2 struct{
id int
age int
}
type reDB interface {
my_print()
}
func (r *s1) my_print(){
fmt.Print(s1.id)
}
func (r *s2) my_print(){
fmt.Print(s1.id)
}
func queryDb() reDB{
...
}

Conditional variable declaration in golang?

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{}

Resources