How can I store different error interface implementations together and then use them for type comparison in Go? - pointers

I'm trying to write a table test in go where the test cases will result in different errors. I then want to check if the type of the error matches a an error type defined in the test case, using errors.As(). Each test case is defined by a struct, so there needs to be a type in the struct that can hold any implementation of the interface error, which is then also to verify that the correct type was returned in the test.
I have tried defining the struct as follows
type testCase struct {
testInput string
expectedError error
}
I also have a number of custom errors that implement the error interface, lets say one is called myCustomError
I then declare a variable of that struct like this:
mTest := testCase{
testInput: "some failing string",
expectedError: myCustomError{},
}
if I then do the test like this...
err := someFunc(mTest.testInput)
if errors.As(err, &mTest.expectedError) {
// test have succeeded
}
... the if statement will always return true, regardless of which of my custom error types is returned.
I made a minimal example if this behavior on the Go Playground here: https://play.golang.org/p/uMdbMvfcdQi
In the playground example, I expect the string "matching myError1" to be printed twice, but instead it also matches myError2 when the value is stored as a plain error before it is used to check the type of the variable err.
Is is even possible to do something like this?

Store a pointer to the target value in the test case.
type testCase struct {
testInput string
expectedError interface{}
}
mTest := testCase{
testInput: "some failing string",
expectedError: &myCustomError{},
}
err := someFunc(mTest.testInput)
if errors.As(err, mTest.expectedError) {
// test have succeeded
}
Minimal example: https://play.golang.org/p/igJy9L_ui73

Related

How do I handle optional query parameters for a Go using Mux properly?

I'm making an API server using GoLang and I am using Mux as the HTTP router. I have one endpoint in my app, /tasks. When I hit that endpoint, I get back an array of results, which is as expected. Now, I want to build upon that and add an optional query parameter into the URL to only return N results, like so: /tasks?num=5 which would only return 5 results. I have accomplished this using the handler below:
vars := r.URL.Query()
t := task{}
if numOfTasksParam, ok := vars["num"]; ok {
fmt.Printf("%+v", numOfTasksParam[0])
numOfTasks, err := strconv.Atoi(vars.Get("num"))
//return only n number of results
} else {
//return the entire result set
}
I devised this solution because I discovered that URL.Query() returns a map of the query parameters and therefore, I can just check to see if that map contained the key of "num". If so, the client wants N number of results. If not, the client must want the whole result set.
The main issue I have with this approach is that when I go to check if the keys exists, I make a temporary variable called numOfTasksParam which holds the query parameter value, but it holds the value as a string and I need a int. Therefore, I must use the numOfTasksParam somehow and then create another variable to convert that to an integer value.
Is there more succinct or convenient way of checking if a query parameter exists in the request URL?
This is probably the most succinct, and works because Get returns an empty string if the parameter isn't set, which Atoi will fail to parse:
vars := r.URL.Query()
t := task{}
if numOfTasks, err := strconv.Atoi(vars.Get("num")); err == nil {
//return only numOfTasks number of results
} else {
//return the entire result set
}
The price you pay for having less code is that if a user passes an invalid value like ?num=taco, it will be treated as if they passed nothing, rather than telling the user they passed something unusable. This may or may not be what you want. It is also slightly less efficient, because it will run Atoi even if the value is known to be empty.

Golang type assertion for list of items

Im calling a API and it returns a dictionary(map) with a list of items as values.
For ex:-
result= {'outputs':[{'state':'md','country':'us'}, {'state':'ny','country':'ny'}]}
The above data is how the data represented in python.
In Python, I directly use result['outputs'][0] to access the list of elements in the list.
In Golang, the same API returns the data but when I try to access the data as result['outputs'][0]
Get this error:-
invalid operation: result["outputs"][0] (type interface {} does not support indexing)
Looks like I need to do a type conversion, what should I use to type convert,
I tried this
result["outputs"][0].(List)
result["outputs"][0].([])
but both throws me an error.
I checked the type of the returned item and this is it - []interface {}
What should be my type conversion?
You wrote the type of the value is []interface{}, so then do a type assertion asserting that type.
Also note that you first have to type assert, and index later, e.g.:
outputs := result["outputs"].([]interface{})
firstOutput := outputs[0]
Also note that the (static) type of firstOutput will again be interface{}. To access its content, you will need another type assertion, most likely a map[string]interface{} or a map[interface{}]interface{}.
If you can, model your data with structs so you don't have to do this "type assertion nonsense".
Also note that there are 3rd party libs that support easy "navigation" inside dynamic objects such as yours. For one, there's github.com/icza/dyno (disclosure: I'm the author).
Using dyno, getting the first output would be like:
firstOutput, err := dyno.Get(result, "outputs", 0)
To get the country of the first output:
country, err := dyno.Get(result, "outputs", 0, "country")
You can also "reuse" previously looked up values, like this:
firstOutput, err := dyno.Get(result, "outputs", 0)
// check error
country, err := dyno.Get(firstOutput, "country")
// check error

golang function return interface pointer

Can some one help me understand why it's failing to use the syntax like [Error 1] and [Error 2]?, why [ok 1] is possible and working just fine.
Is the basic design to use Animal as field to serve as generic type good? or any thing bad about it? or any better solution suggested?
package main
import (
pp "github.com/davecgh/go-spew/spew"
)
type Cat struct {
Name string
Age int
}
type Animal interface{}
type House struct {
Name string
Pet *Animal
}
func config() *Animal {
c := Cat{"miao miao", 12}
// return &Animal(c) //fail to take address directly [Error 1]
// return &(Animal(c)) //fail to take address directly [Error 2]
a := Animal(c) //[Ok 1]
return &a
}
func main() {
pp.Dump(config())
pp.Dump(*config())
pp.Dump((*config()).(Cat)) //<-------- we want this
pp.Dump((*config()).(Cat).Name)
pp.Dump("---------------")
cfg := config()
pp.Dump(&cfg)
pp.Dump(*cfg)
pp.Dump((*cfg).(Cat)) //<-------- we want this
pp.Dump((*cfg).(Cat).Name)
pp.Dump("---------------")
}
Ok, two thing:
You cannot take the address of the result of a conversion directly, as it is not "addressable". See the section of the spec about the address-of operator for more information.
Why are you using a pointer to an interface at all? In all my projects I have only ever used an interface pointer once. An interface pointer is basically a pointer to a pointer, sometimes needed, but very rare. Internally interfaces are a type/pointer pair. So unless you need to modify the interface value instead of the value the interface holds then you do not need a pointer. This post may be of interest to you.

Convert Value type to Map in Golang?

I'm getting this return value from a function call in the "reflect" package:
< map[string]string Value >.
Wondering if I can access the actual map inside the return value and if so, how?
EDIT:
So this is where I'm making the call which returns the Value object.
It returns [< map[string]string Value >] to which I grab the first object in that array. However, I'm not sure how to convert [< map[string]string Value >] into a regular map.
view_args := reflect.ValueOf(&controller_ref).MethodByName(action_name).Call(in)
Most reflect Value objects can be converted back to a interface{} value using the .Interface() method.
After obtaining this value, you can assert it back to the map you want. Example (play):
m := map[string]int{"foo": 1, "bar": 3}
v := reflect.ValueOf(m)
i := v.Interface()
a := i.(map[string]int)
println(a["foo"]) // 1
In the example above, m is your original map and v is the reflected value. The interface value i, acquired by the Interface method is asserted to be of type map[string]int and this value is used as such in the last line.
To turn the value in a reflect.Value into an interface{}, you use iface := v.Interface(). Then, to access that, you use a type assertion or type switch.
If you know you're getting a map[string]string the assertion is simply m := iface.(map[string]string). If there's a handful of possibilities, the type switch to handle them all looks like:
switch item := iface.(type) {
case map[string]string:
fmt.Println("it's a map, and key \"key\" is", item["key"])
case string:
fmt.Println("it's a string:", item)
default:
// optional--code that runs if it's none of the above types
// could use reflect to access the object if that makes sense
// or could do an error return or panic if appropriate
fmt.Println("unknown type")
}
Of course, that only works if you can write out all the concrete types you're interested out in the code. If you don't know the possible types at compile time, you have to use methods like v.MapKeys() and v.MapIndex(key) to work more with the reflect.Value, and, in my experience, that involves a long time looking at the reflect docs and is often verbose and pretty tricky.

Golang reflection.Value behaviour

I'm currently getting desperate over the behaviour of golangs reflect package, which to me doesn't seem consistent at all.
1) As far as I understand it, a reflect.Value seems to carry a pointer to the underlying value.
E.g. if I call
var s string
v1 := reflect.ValueOf(&s).Elem()
v2 := v1
v2.SetString("Hello World!")
fmt.Println(s)
It prints me "Hello World!".
However, this doesn't seem to hold true for a reflect.Value obtained by a call to Field().
val := ... //Assign a reflect.Value to it
nextval := val.Field(0) //Make sure that Field exists and is of type map
nextval = reflect.MakeMap(reflect.MapOf(KEY, ELEM))
nextval.SetMapIndex(Some_value_of_type_KEY, Something_of_type_ELEM)
fmt.Println(nextval.MapKeys()
fmt.Println(val.Field(index).MapKeys())
This prints
[Some_value_of_type_KEY]
[]
which is a major annoyance. Anyone knows why this is the case?
===================================================
2) Consider the function
func Test(v interface{}) {
val := reflect.ValueOf(v)
if val.Kind() != reflect.Struct {
fmt.Println("It is a struct")
}
}
If I call it with any struct as an argument it prints "This is a struct".
However, I won't be able to assign new values to stuff inside v by using val,
due to the value not being addressable. Working around by the following:
func Test(v interface{}) {
val := reflect.ValueOf(&v).Elem()
if val.Kind() != reflect.Struct {
fmt.Println("This never get's printed!")
}
}
According to the doc, I would assume, that by taking the '&' I use a pointer to v and by the call of Elem() I get the element it points to, therefore val.Kind() should still return the same thing. It doesn't. val.Kind() now is a reflect.Interface.
Is there a way of not having to go
valForTestingKind := reflect.ValueOf(v)
valForSettingNewValue := reflect.ValueOf(&v).Elem()
as this somehow feels wrong.
Part 1:
By assigning to nextval, you are breaking its association with the original val. Instead, use the Set() method.
nextval.Set(reflect.MakeMap(reflect.MapOf(KEY, ELEM)))
Set() is the equivalent of assignment in the reflection world. Of course, you must make sure it is assignable using reflect.ValueOf(&v).Elem() as you do in your first code example.
Part 2:
The issue here is that you have another level of indirection. v is of type interface{} and has a concrete value whose type is of Kind struct. Just like with every function that accepts an interface typed parameter, when you call reflect.ValueOf, the parameter is automatically converted to that type. However, converting an interface to another interface results in the concrete value being reboxed in the new interface type. The information of the type before it was reboxed is lost. As an example, a function that accepts an io.Writer would not know that the calling function considered it an io.ReaderWriter.
In this context, it means that reflect.ValueOf cannot tell if you passed an os.File (some struct) or a file boxed in an interface{}. It assumes you passed an os.File and shows you the Kind "struct".
However, when you pass a pointer to an interface{}, you are passing an interface{} variable that can be modified. You are not passing the underlying concrete type and that has important consequences. You can .Set() anything, not just what the original concrete type allows. You also can't edit individual fields as anything in an interface{} is not assignable. If the concrete type is in fact a pointer, you can do a fourth dereference (.Elem()) and modify fields from there.
So, what does this mean in terms of code?
//let v = an interface{} with a concrete type of SomeStruct
val := reflect.ValueOf(&v).Elem()
fmt.Println(val.Elem().Kind()) // struct
val.Elem().Field(0).Set(10) // PANIC! Field isn't assignable.
val.Set("a string which is not a SomeStruct")
fmt.Println(val.Elem().Kind()) // string
I made an example here: http://play.golang.org/p/6MULn3KoNh
I want to talk about your second block of code:
val := ... //Assign a reflect.Value to it
nextval := val.Field(0) //Make sure that Field exists and is of type map
nextval = reflect.MakeMap(reflect.MapOf(KEY, ELEM))
nextval.SetMapIndex(Some_value_of_type_KEY, Something_of_type_ELEM)
fmt.Println(nextval.MapKeys()
fmt.Println(val.Field(index).MapKeys())
On the third line, you are reassigning a new, different object to the variable nextval. Shouldn't you call some kind of setting method on nextval instead of reassigning it? In your first example, you called SetString but in this example you are just reassigning the variable and that might be why the behavior is different. After you reassign the variable, nextval will no longer be connected in any way to val.Field(0). Also, what is index?
If this does not explain your problem, please edit the question to contain a short, self-contained, correct, compilable example ( SSCCE ). I want to be able to post it into the text box on the front page of golang.org in order to see the problem. You should always post an SSCCE when possible.
You have not shown a complete and compilable code. Do you pass a pointer to a struct or do you pass the struct by value? In the later case reflection cannot mutate it.
Values stored in a map are not addressable even when not using reflection.
http://play.golang.org/p/wYLeJ3W4R2
http://play.golang.org/p/ttUGBVh1lc
https://groups.google.com/forum/#!topic/golang-nuts/jzjEXoc9FwU
https://groups.google.com/forum/#!topic/golang-nuts/V_5kwzwKJAY

Resources