Assign empty slice without referring to its type? - go

My code calls a library function which looks roughly like this:
func Search() ([]myLibrary.SomeObject, error) {
var results []apiv17.SomeObject
// ...
if (resultsFound) {
results = append(results, someResult)
}
return results
}
...and my code calls it and then marshals it to JSON.
results, err := myLibrary.Search()
bytes, err := json.Marshal(results)
Now the problem is that because of the way the Search function is written (and let's assume we can't change it), it'll return an uninitialized nil slice if there are no results. And unfortunately, there is no way to configure encoding/json to encode nil slices as [] (see e.g. this proposal with ongoing discussion).
Explicitly checking for nil solves the problem:
results, err := myLibrary.Search()
if results == nil {
results = []apiv17.SomeObject{}
}
bytes, err := json.Marshal(results)
...but it also adds an explicit dependency on the return type, apiv17.SomeObject. That's inconvenient because that type frequently changes in the library. E.g. in the next library version it might be apiv18.SomeObject.
With the nil check above, I'll have to update my code every time that happens.
Is there any way to avoid this and assign an empty, non-nil slice to the variable without explicitly referring to its type? Something like this:
results = [](type of results){}

Go 1.18
You can use a generic function that captures the slice's base type and returns a slice of length zero:
func echo[T any](v []T) []T {
return make([]T, 0)
}
func main() {
n := foo.GetFooBar()
if n == nil {
n = echo(n) // no need to refer to apiv17 here
}
bytes, _ := json.Marshal(n)
fmt.Println(string(bytes)) // prints []
}
The purpose of requiring a regular argument v []T in echo is to allow type inference to unify the slice []apiv17.SomeObject with the argument []T and infer T as the base type apiv17.SomeObject, so that you can call it just as echo(n) and no explicit type parameter.
The package apiv17 is of course known at compile time because it's transitively imported via myPackage, so you can take advantage of this and type inference to avoid adding an explicit import statement for apiv17.
This is how it looks like on the multi-file playground: https://go.dev/play/p/4ycTkaGLFpo
The type is declared in bar package, but main only imports play.ground/foo and only uses foo.GetFooBar.
Go 1.17 and below
Reflection. Just change the echo function from above to taking an interface{} argument (there's no any in Go 1.17, remember?) and do the deed with reflect.MakeSlice:
func set(v interface{}) {
rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr {
panic("not a ptr")
}
reflect.Indirect(rv).Set(reflect.MakeSlice(rv.Type().Elem(), 0, 0))
}
Then pass a pointer to the slice, so that you can set its value with reflection.
func main() {
n := foo.GetFooBar()
if n == nil {
set(&n)
}
fmt.Printf("type: %T, val: %v, is nil: %t\n", n, n, n == nil)
// type: []bar.FooBar, val: [], is nil: false
bytes, _ := json.Marshal(n)
fmt.Println(string(bytes)) // prints [] again
}
Go 1.17 playground: https://go.dev/play/p/4jMkr22LMF7?v=goprev

The other answer describes how to create an empty slice.
But you can solve your original issue much simpler: if results is nil, you don't need to create a empty slice, regardless of whatever element type it would have, the JSON marshaling would be [] anyway. So if results is nil, no need to call json.Marshal(), just "output" []:
results, err := myLibrary.Search()
var bytes []byte
if results == nil {
bytes = []byte{'[', ']' } // JSON marshaling result is "[]"
} else {
bytes, err = json.Marshal(results)
// Handle error
}

Related

How to get the underlying value of pointer type in Go?

I found this question How to get a pointer to the underlying value of an Interface{} in Go, but it looks too unsafe for me.
Of course I could use * to unpack it but I have to add nil check every time on caller side.
x := &some_type
fmt.Println(*x)
I am expecting the function that return default value of the base type if the pointer is nil.
x := Unpacker(some_type)
I'd just check for nil with an if statement. It's the reasonable thing to do. Though if you want to explore alternatives, read on.
In Go 1.18 you can accomplish this with a simple generic function:
func val[T any](v *T) T {
if v != nil {
return *v
}
return *new(T) // zero value of T
}
However this works only for pointer types in the form *T. There's other types in Go which have nil as zero value and are not pointers. Or this function could still return nil if you pass a pointer to such a type, like *[]int. Unfortunately there isn't a handy way to declare a constraint for all possible nillable types1.
With Go 1.17 and below you can use a type switch if the set of possible types is known, but then have to assert the result. This has the minor advantage of permitting ad-hoc initialization of nillable types:
func val(v interface{}) interface{} {
switch t := v.(type) {
case *string:
if t != nil {
return *t
}
return ""
case *[]string:
if t != nil {
return *t
}
return []string{}
default:
panic("unexpected type")
}
}
Or just use reflection, with the same limitations of having to assert the return, or risking to return nil again:
func val(v interface{}) interface{} {
t := reflect.TypeOf(v)
if t == nil || t.Kind() != reflect.Ptr {
panic("invalid input")
}
rv := reflect.ValueOf(v)
if rv.IsNil() {
return reflect.Zero(rv.Type().Elem()).Interface()
}
return v
}
Playground: https://go.dev/play/p/9dk0hWay90j
1: mainly because such a constraint would have to capture the key and/or value types of the map type, and decide what to (arbitrarily) return in those cases.
I am accepting another answer, but here is what I tried which apparently work for primitives too.
func Unwrap[T any](x *T) (r T) {
if x != nil {
r = *x
}
return
}

Check named return error using defer function

Hi I want to write a generic function to trace error message when a function returns error. So I wrote this:
func TraceError1(err *error) {
if err != nil && *err != nil {
pc := make([]uintptr, 15)
n := runtime.Callers(2, pc)
frames := runtime.CallersFrames(pc[:n])
frame, _ := frames.Next()
fmt.Printf("%s:%d %s\n", frame.File, frame.Line, frame.Function)
}
}
func TraceError2(err error) {
if err != nil {
pc := make([]uintptr, 15)
n := runtime.Callers(2, pc)
frames := runtime.CallersFrames(pc[:n])
frame, _ := frames.Next()
fmt.Printf("%s:%d %s\n", frame.File, frame.Line, frame.Function)
}
}
func foo() (err error) {
defer TraceError1(&err)
defer TraceError2(err)
fmt.Println("do something")
return fmt.Errorf("haha")
}
TraceError1 works but TraceError2 didn't. In my understanding, error is an interface so it is a pointer/address, why do I need to pass its address? Why TraceError2 cannot work? Thanks.
In case of TraceError1 you are passing a pointer to the named return value err. The pointer is non-nil, but the value it points at (err) is nil (at the time of defer). However, it is not yet evaluated (dereferenced) because TraceError1 has not yet been called. By the time the function does run (after foo returns) and the pointer gets dereferenced, the value of err has been updated (by the return statement inside foo).
However, in case of TraceError2, a nil interface value is passed, which will stay nil even when TraceError2 executes eventually.
Here is a simpler example:
package main
import "fmt"
func intByValue(i int) {
fmt.Printf("i = %d\n", i)
// ^--- `i` is an integer value
// --- whatever i was passed to the function, gets printed
}
func intByRef(i *int) {
var v int = *i // i is a pointer to an int, which gets dereferenced here
// the *address* where the actual value resides was passed
// while the address stays the same, its value can change before
// i is dereferenced, and its value stored in v.
fmt.Printf("i = %d\n", v)
}
func main() {
var i int
defer intByValue(i) // passed the *value* of i, which is 0 right now
defer intByRef(&i) // passed a *pointer* to i, which contains 0 right now
i = 100 // before intByRef could "dereference" its argument, the value that it
// contained has been updated
// intByRef gets called, dereferences the value, finds 100, prints it.
// intByValue gets called, finds 0, prints it
// result should be:
// i = 100
// i = 0
}
So unfortunately, if you want the ability to update the error (e.g. by returning a named return value) before it gets used by the deferred function, you are going to have to pass around pointers to the variable.
In other words, TraceError2 is simply not suited for your use case.
Edit: use correct terminology and (questionably) improve example code.
As go blog explained
The behavior of defer statements is straightforward and predictable.
There are three simple rules:
A deferred function's arguments are evaluated when the defer statement is evaluated.
Deferred function calls are executed in Last In First Out order after the surrounding function returns.
Deferred functions may read and assign to the returning function's named return values.
According to first point, when you call defer TraceError2(err) , that err = nil and that is the value pass to the TraceError2 function.
TraceError1(err *error) works because it is getting a pointer to err, and that pointer value is assigned before defer func TraceError1 is executed.
Simple example code to explain the behaviour.
package main
import (
"fmt"
"runtime"
)
func main() {
i := 0
defer func(i int) {
fmt.Printf("%d\n",i) //Output: 0
}(i)
defer func(i *int) {
defer fmt.Printf("%d\n",*i) //Output: 1
}(&i)
i++
}

Cast interface to concrete type - type switch

I am looking for a way to cast an interface into the concrete type to save a lot of source code.
The initial situation are two functions of a webserver handler. They differ only in that one function decodes an array of structs and the other decodes a single struct and stores it in the database. The functions which have to be called for saving are identical depending on the type.
To decide whether an array or a struct is passed, it is tried to cast the interface into the type and then to pass this appropriately as a parameter of the function. Similar as it is described in the documentation and in the stackoverflow post.
However, I do not get the concrete type as expected and the program always runs into the default section. What am I doing wrong or have I not taken into account?
These are the outputs of the default section:
# interface is a struct
... or a single repository struct: map[string]interface{}
# interface is an array of structs
... or a single repository struct: []interface{}
Below is the source code with the functions
func (rh *RouteHandler) AddOrUpdateRepository(rw http.ResponseWriter, req *http.Request) {
repository := new(types.Repository)
rh.addOrUpdateRepositories(rw, req, repository)
}
func (rh *RouteHandler) AddOrUpdateRepositories(rw http.ResponseWriter, req *http.Request) {
repositories := make([]*types.Repository, 0)
rh.addOrUpdateRepositories(rw, req, repositories)
}
func (rh *RouteHandler) addOrUpdateRepositories(rw http.ResponseWriter, req *http.Request, v interface{}) {
defer req.Body.Close()
switch req.Header.Get("Content-Type") {
case "application/xml":
xmlDecoder := xml.NewDecoder(req.Body)
err := xmlDecoder.Decode(&v)
if err != nil {
rw.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(rw, "Failed to decode repositories or repository")
rh.ulogger.Error("Failed to decode repositories or repository: %v", err)
return
}
case "application/json":
fallthrough
default:
jsonDecoder := json.NewDecoder(req.Body)
err := jsonDecoder.Decode(&v)
if err != nil {
rw.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(rw, "Failed to decode repositories or repository")
rh.ulogger.Error("Failed to decode repositories or repository: %v", err)
return
}
}
var err error
switch x := v.(type) {
case map[string]*types.Repository:
for _, repository := range x {
err = rh.manager.AddOrUpdateRepository(context.Background(), repository)
}
case *types.Repository:
err = rh.manager.AddOrUpdateRepository(context.Background(), x)
case map[string][]*types.Repository:
for i := range x {
for j := range x[i] {
err = rh.manager.AddOrUpdateRepository(context.Background(), x[i][j])
}
}
case []*types.Repository:
err = rh.manager.AddOrUpdateRepository(context.Background(), x...)
case nil:
rw.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(rw, "Failed to cast interface")
rh.ulogger.Error("Failed to cast interface. Interface is a type of nil")
return
default:
rw.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(rw, "Failed to cast interface")
rh.ulogger.Error("Failed to cast interface. Interface does not match onto an array of repositories or a single repository struct: %T", x)
return
}
if err != nil {
rw.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(rw, "Failed to add repositories or repository")
rh.ulogger.Error("Failed to add repositories or repository: %v", err)
return
}
rw.WriteHeader(http.StatusCreated)
}
(Simplified a bit.)
You have a function with the following signature:
func addOrUpdateRepositories(v interface{})
and then you call it like this:
repository := new(types.Repository)
addOrUpdateRepositories(repository)
and like this:
repositories := make([]*types.Repository, 0)
addOrUpdateRepositories(repositories)
In the first call, the concrete type of the value stored in v will be *types.Repository (as new returns a pointer to the allocated value) and in the second call the concrete type of the value stored in v will be []*types.Repository—because that's what make was told to create.
Now you do a type-switch on v, which reads:
switch x := v.(type) {
case map[string]*types.Repository:
case map[string][]*types.Repository:
case nil:
default:
}
Leaving aside the case that if you do not call addOrUpdateRepositories passing it a nil v which cannot happen in the snippet from your question, the switch will always pick the default branch because the type of the concrete value stored in v is never map[string]*types.Repository or map[string][]*types.Repository.
I am not sure why you fail to see this, so probably you should refine your question or may be try to clear up your confusion in a comment to my answer?
Another shot in the dark: type conversions (note that Go does not have type casts, as #Flimzy pointed out) and type switches in Go do not actually change the underlying representation of the value they operate on—except for the limited set of ("everyone expects this") cases such as type-converting a float64 to int64, which are precisely documented.
So you cannot take a []*types.Repository (a slice of pointers to values of type types.Repository) and somehow force it "to become" map[string][]*types.Repository: that'd be a nonsensical thing to do for a number of reasons, with the most glaring being this: if you were writing the Go compiler, how would you carry out such a "type cast"? Suppose you were to really allocate a map, but then which key in that map should have been assigned the original (source) slice? What about type-converting a []*types.Repository to struct {foo []*types.Repository; bar []*types.Repository}?

Golang address operators and (*int)(Type) syntax

Starting to play around with golang and was looking at a custom json.Unmarshal. In a blog post the had the following:
type FlexInt int
func (fi *FlexInt) UnmarshalJSON(data []byte) error {
if data[0] != '"' {
return json.Unmarshal(data, (*int)(fi))
}
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
i, err := strconv.Atoi(s)
if err != nil {
return err
}
*fi = FlexInt(i)
return nil
}
And I understand what it is doing - but I dont understand (*int)(fi) part. Looking at the value of the fi pointer it is the same as (*int)(fi) - (*int)(fi) == fi. Yet when I change that line to simply fi it then does an infinite loop
The expression converts fi to an *int. The result contains the same address, but has a different type.
If a *FlexInt is passed to json.Unmarshal, then json.Unmarshal will call the *FlexInt.UnmarshalJSON method which calls json.Unmarshal and so on.
It's the same pointer, but with a different type. When json.Unmarshal is called with an interface{} that contains a FlexInt*, it calls FlexInt's UnmarshalJSON method. When it's called with an interface{} that contains an int*, it uses the builtin behavior. Since FlexInt and int have the same underlying type, it's acceptable to convert a pointer to one into a pointer to the other, but it's the "actual" type that the interface will be marked with.

Golang update pass by reference value

I am calling a function to do a http request, two pass by reference parameter is used for the function. I pass the []byte to v interface. I want the function to update the v interface reference value. The response body is a string, I want to pass the string value to v interface. However, tried many ways but not success.
Here is the code, you can see I declare byts as v.(*[]byte) in order to make v updated with the string value of response body. But it does not work. The v is always nil. Please suggest any way to make v can be updated with the string value.
func (s *BackendConfiguration) Do(req *http.Request, v interface{}) error {
res, err := s.HTTPClient.Do(req)
defer res.Body.Close()
resBody, err := ioutil.ReadAll(res.Body)
if v != nil {
byts, ok := v.(*[]byte)
if len(resBody) > 0 {
byts = append(byts, resBody...)
return nil
}
}
}
return nil
}
Well, the main reason this does not work is because you think of "call by reference", a concept completely unknown to Go. Absolutely everything is called by value in Go and once you spell out what is a byte slice, a pointer to a byte slice, a pointer to byte slice wrapped inside an interface, a copy of the pointer to a byte slice extracted from the interface, and so on you'll see how to update the value the pointer to byte slice points to:
package main
import "fmt"
func f(v interface{}) {
pbs := v.(*[]byte)
*pbs = append(*pbs, []byte{9,8,7}...)
}
func main() {
bs := []byte{1,2,3}
pbs := &bs
var v interface{} = pbs
f(v)
fmt.Printf("%v\n", *pbs)
}

Resources