how to assign only on return value of a function to field of an struct in golang? [duplicate] - go

This question already has answers here:
Multiple values in single-value context
(6 answers)
Closed 5 years ago.
let's say we have a struct like this:
type Data struct {
a int
}
and we want to get a single return value of a function that returns multiple values and assign it to an object of Data, for example
data := Data {
a: strconv.Atoi("1000")
}
the code above does not work because Atoi returns two value, a number and an error, so we need to handle the extra value (error) somehow, but in my case, I do not need to evaluate error value and it is not possible to dismiss it using _ keyword.
how can I achieve this when initializing a struct, I want to get rid of the error return value

There is no generic way to get just one of returned parameters (Maybe you could implement something with reflect package that returns interface{}).
Other than that it's not good to ignore errors. If you are sure that there's no error implement a helper function like this:
func myAtoi(s string) int {
i, err := strconv.Atoi(s)
if err != nil {
panic(err)
}
return i
}
data := Data {
a: myAtoi("1000")
}

Related

cannot use mapToPrint (variable of type map[string]CustomStruct) as type map[string]any - golang [duplicate]

This question already has an answer here:
Gomock cannot use type map[string]*mockFoo as map[string]foo
(1 answer)
Closed 4 months ago.
In my function I was receiving an argument that contained a map for which the value's type was any. I would have thought that any type could therefore be sent, but I got the following error when I tired to use map[string]CustomStruct:
cannot use mapToPrint (variable of type map[string]CustomStruct) as type map[string]any in argument to printMap.
If I create the map with type's value any, everything works, including the assignment of CustomStruct to map values.
Here is a reproducing example:
type CustomStruct struct {
name string
}
func main() {
mapToPrint := make(map[string]CustomStruct, 0)
mapToPrint["a"] = CustomStruct{"a"}
mapToPrint["b"] = CustomStruct{"b"}
printMap(mapToPrint)
}
func printMap(mapToPrint map[string]any) {
for key, value := range mapToPrint {
fmt.Println(key, value)
}
}
go.dev
As the go FAQ says here:
It is disallowed by the language specification because the two types do not have the same representation in memory.
As the FAQ suggests, simply copy the data from your map into a map with value type any, and send it like so to the function:
printableMap := make(map[string]any, len(mapToPrint))
for key, value := range mapToPrint {
printableMap[key] = value
}

Is it possible to conditionally implement the comma ok idiom in go, like map lookup? [duplicate]

This question already has answers here:
Return map like 'ok' in Golang on normal functions
(2 answers)
Closed 6 months ago.
In golang, you can fetch a key from a map using the obvious syntax:
someMap := map[string]string{
//... contents
}
value := someMap["key1"]
// If "key1" exists in someMap, then the value will be returned; else empty string.
Problem: You can't tell missing keys apart from legitimate empty string values
So, you can test for presence using the comma ok idiom
value, ok := someMap["key1"]
if ok {
// we know that "key1" was in the map, even if value is empty string
} else {
// we know that "key1" was NOT in the map
}
What this looks like is that there are two different overloads of the map lookup method, one which returns just a single map value result, and one which returns the (value, bool) result, and the compiler seems to be selecting the overload based on how many return values you've said you'd like to receive.
This is quite nice, and I was wondering if it was possible to implement this on my own functions?
E.g:
func fetchValue() (string, bool) {
return "", true
}
func testMain() {
// This works fine, as expected
val, ok := fetchValue()
if ok {
fmt.Println(val)
}
// COMPILE ERROR: Assignment count mismatch: 1 = 2.
val2 := fetchValue()
}
// COMPILE ERROR: fetchValue redeclared in this package
func fetchValue() string {
return ""
}
Is this possible? or is it secret special language sauce that only works for the builtin map type and nothing else?
You cannot define your own function that sometimes returns 2 values, sometimes 1.
You can do:
val, ok := fetchValue()
if !ok {
// failure path.
}
or
val, _ := fetchValue()
// not checking for failure.

How to range over slice of a custom type

I'm trying to write in Go custom cache for Google DataStore (more precisely - a wrapper around one of existing cache libraries). At cache initialisation, it should accept any custom type of struct (with appropriately-defined datastore fields), which then would be the basis for all items stored. The idea is that cache can be created/initialised for various types which reflect the structure of a particular DataStore entry (CustomEntry)
Approach 1 - store reflect.Type and use it. Problem encountered - can't iterate over a slice of a custom type
type CustomEntry struct {
Data struct {
name string `datastore:"name,noindex"`
address []string `datastore:"address,noindex"`
} `datastore:"data,noindex"`
}
func (cache *MyCache) CacheData(dataQuery string, dataType reflect.Type) {
slice := reflect.MakeSlice(reflect.SliceOf(dataType), 10, 10)
if keys, err := DataStoreClient.GetAll(cache.ctx, datastore.NewQuery(dataQuery), &slice); err != nil {
//handle error
} else {
for i, dataEntry:= range slice {
// ERROR: Cannot range over 'slice' (type Value)
cache.Set(keys[i].Name, dataEntry)
}
}
//usage: Cache.CacheData("Person", reflect.TypeOf(CustomEntry{})
Approach 2 - accept an array of interfaces as arguments. Problem encountered = []CustomEntry is not []interface{}
func (cache *MyCache) CacheData(dataQuery string, dataType []interface{}) {
if keys, err := DataStoreClient.GetAll(cache.ctx, datastore.NewQuery(dataQuery), &dataType); err != nil {
//handle error
} else {
for i, dataEntry:= range slice {
// this seems to work fine
cache.Set(keys[i].Name, dataEntry)
}
}
//usage:
var dataType []CustomEntry
Cache.CacheData("Person", data)
// ERROR: Cannot use 'data' (type []CustomEntry) as type []interface{}
Any suggestions would be highly appreciated.
I have found a solution and thought it might be worth sharing in case anyone else has a similar problem.
The easiest way is to initiate a slice of structs which the DataStore is expected to receive, and then to pass a pointer to it as an argument (interface{}) into the desired function. DataStore, similarly to a few unmarshaling functions (I have tried with JSON package) will be able to successfully append the data to it.
Trying to dynamically create the slice within the function, given a certain Type, which would be then accepted by a function (such as DataStore client) might be quite difficult (I have not managed to find a way to do it). Similarly, passing a slice of interfaces (to allow for easy iteration) only complicates things.
Secondly, in order to iterate over the data (e.g. to store it in cache), it is necessary to:
(1) retrieve the underlying value of the interface (i.e. the pointer itself) - this can be achieved using reflect.ValueOf(pointerInterface),
(2) dereference the pointer so that we obtain access to the underlying, iterable slice of structs - this can be done by invoking .Elem(),
(3) iterate over the underlying slice using .Index(i) method (range will not accept an interface, even if the underlying type is iterable).
Naturally, adding a number of switch-case statements might be appropriate to ensure that any errors are caught rather than cause a runtime panic.
Hence the following code provides a working solution to the above problem:
In main:
var data []customEntry
c.CacheData("Person",&data)
And the function itself:
func (cache *MyCache) CacheData(dataQuery string, data interface{}) error {
if keys, err := DataStoreClient.GetAll(cache.ctx, datastore.NewQuery(dataQuery), data); err != nil {
return err
} else {
s := reflect.ValueOf(data).Elem()
for i := 0; i < s.Len(); i++ {
cache.Set(keys[i].Name, s.Index(i), 1)
}
}
}

How to use a reflect.Type to perform a type assertion [duplicate]

This question already has answers here:
golang type assertion using reflect.Typeof()
(6 answers)
Closed 8 months ago.
I know reflection is generally frowned upon in go but for my current purposes Im pretty sure it is the best solution.
Essentially my project is cli tool which will output an xml query based on incoming commands and return the corresponding result.
There is some boiler plate code for each command request where default values are populated and supplied values validated.
So I have a series of Command objects based on a Command struct as follows:
type Command struct {
Name string
Request interface{}
RequestType reflect.Type
Response interface{}
RegisterFunc func(parentCmd *cobra.Command, cmd *Command) error
}
For the most part I really don't care about the types of the request/response (just xml encode/decode). However I need to briefly cast it to a concrete type to validate with struct annotations
So for example I might do something like this:
var ccReq *CreateCredentialRequest
var set bool
if ccReq, set = command.Request.(*CreateCredentialRequest); !set {
log.Fatal(errors.New("invalid request type"))
}
result, err := govalidator.ValidateStruct(ccReq)
if err != nil {
println("error: " + err.Error())
os.Exit(1)
}
However in an ideal would I would like to handle this generically for all commands, something like this:
var ccReq *CreateCredentialRequest
var set bool
if ccReq, set = command.Request.(command.RequestType); !set {
log.Fatal(errors.New("invalid request type"))
}
However this results in the error:
command.RequestType is not a type
So, how can I store the value of a type for a later type assertion
Note: Following discussion in comments with JimB it seems that i do not actually need the concrete type for validation purposes (interface is fine) but I still need further down to assert the response type to provide a custom response handler
From the reflect.Type docs:
Type values are comparable, such as with the == operator, so they can be used as map keys. Two Type values are equal if they represent identical types.
If you want to compare underlying types, compare the reflect.Type values directly:
if reflect.TypeOf(command.Request) != command.RequestType {
log.Fatal(errors.New("invalid request type"))
}

Pass a result from multi-returing function to another one taking only one argument in Go

Is it possible to pass a result form function which returns multiple values directly to function which accepts only one? Example:
func MarshallCommandMap(mapToMarshall map[string]string) string {
return string(json.Marshal(mapToMarshall))
}
The example above will cause compilation error:multiple-value json.Marshal() in single-value context. I know it is possible to get same result with additional variable:
func MarshallCommandMap(mapToMarshall map[string]string) string {
marshaledBytes, marshalingError := json.Marshal(mapToMarshall)
if (marshalingError != nil) {
panic(marshalingError)
}
return string(marshaledBytes)
}
But is it possible to pass only first value direclty without any variable?
I think you mean doing something like python's tuple unpacking.
Unfortunately this is not possible in Go (AFAIK).
No you can't, however 2 things with your code.
Shouldn't panic, either return an error or return an empty string.
You can make it shorter.
Example :
func MarshallCommandMap(mapToMarshall map[string]string) string {
js, _ := json.Marshal(mapToMarshall) //ignore the error
return string(js)
}

Resources