How can I check nested pointer easily?
type inner1 struct {
value string
}
type inner2 struct {
value *inner1
}
type outter struct {
value *inner2
}
I have data like this:
o := &outter{
value: &inner2{
value: &inner1{
value: "I need this data",
},
},
}
If I want to get data from this, I need to check for nil pointer.
func printValue(o *outter) (string, bool) {
if o.value != nil {
v1 := o.value
if v1.value != nil {
v2 := v1.value
return v2.value, true
}
}
return "", false
}
Yea, I can do this. But in my real scenario, this nested pointer part is much longer. I will prefer another way.
I have checked this answer, Test for nil values in golang nested stucts. But I need alternative.
How can I accomplish this. Any efficient and better option?
Panic and recover is for exceptional cases. Checking if a pointer is nil is usually not, so you should stay away from it. Checking if a pointer is nil using an if statement is much cleaner than to introduce a deferred function with recover(). Especially as this recover() will stop all other kinds of panic, even those that would result from other reasons than trying to dereference a nil pointer. (Using defer and recover() is also slower than a simple nil check using if.)
If the data is always required to be a non-nil value, you should consider not using a pointer for it. And if the data is always required to be non-nil but for some reason you are required to use a pointer, then this may be a valid case to let your code panic if any of the pointers are still nil.
If it may be nil, then you have to check the nil case and handle it appropriately. You have to be explicit about this, Go doesn't help you omit this check.
To avoid having to check nil in every place, a utility function or method is reasonable. Note that methods can be called even if the receiver is nil which may be useful in such cases.
For example you may attach the following methods:
func (i *inner1) Get() (string, bool) {
if i == nil {
return "", false
}
return i.value, true
}
func (i *inner2) Get() (string, bool) {
if i == nil {
return "", false
}
return i.value.Get()
}
func (o *outter) Get() (string, bool) {
if o == nil {
return "", false
}
return o.value.Get()
}
Note that each Get() method requires to check a single pointer, doesn't matter how complex the data structure is.
Testing it:
o := &outter{
value: &inner2{
value: &inner1{
value: "I need this data",
},
},
}
fmt.Println(o.Get())
o.value.value = nil
fmt.Println(o.Get())
o.value = nil
fmt.Println(o.Get())
o = nil
fmt.Println(o.Get())
Output (try it on the Go Playground):
I need this data true
false
false
false
The above solution hides the internals of outter which is useful for those using outter (doesn't need updating the clients if internals of outter change, just the outter.Get() method).
A similar approach would be to add methods that only return the field of the receiver struct:
func (i *inner1) Value() (string, bool) {
if i == nil {
return "", false
}
return i.value, true
}
func (i *inner2) Inner1() *inner1 {
if i == nil {
return nil
}
return i.value
}
func (o *outter) Inner2() *inner2 {
if o == nil {
return nil
}
return o.value
}
This approach requires clients to know internals of outter, but similarly it does not require any nil checks when using it:
o := &outter{
value: &inner2{
value: &inner1{
value: "I need this data",
},
},
}
fmt.Println(o.Inner2().Inner1().Value())
o.value.value = nil
fmt.Println(o.Inner2().Inner1().Value())
o.value = nil
fmt.Println(o.Inner2().Inner1().Value())
o = nil
fmt.Println(o.Inner2().Inner1().Value())
Output is the same. Try this one on the Go Playground.
I can use panic recovery method. This will solve my problem. But this seems hacky to me.
func printValue(o *outter) (string, bool) {
defer func() (string, bool) {
if r := recover(); r != nil {
return "", false
}
return "", false
}()
return o.value.value.value, true
}
There is no easy way. You may go recover way but it's not idiomatic IMO and you should check that you don't catch other unrelated errors.
I prefer a single if instead of multiple. I don't think of the code below ugly or verbose.
func printValue(o *outter) (string, bool) {
if o.value != nil and o.value.value != nil and o.value.value.value != nil {
return *o.value.value.value, true
}
return "", false
}
Using reflection
func getFieldByName(v interface{}, fields string, sep string) interface{} {
r := reflect.ValueOf(v)
s := strings.Split(fields, sep)
for _, field := range s {
r = reflect.Indirect(r)
if r.IsValid() {
r = reflect.Indirect(r).FieldByName(field)
} else {
return nil
}
}
if r.IsValid() {
return r.Interface()
}
return nil
}
Using Panic Recovery
type safeGetFn func() interface{}
func safeGet(f safeGetFn, d interface{}) (ret interface{}) {
defer func() interface{} {
if r := recover(); r != nil {
ret = d
}
return ret
}()
return f()
}
Example Reflection: https://play.golang.org/p/m0_zQqJm7MY
Example Panic Recovery: https://play.golang.org/p/PNPPBXCvHxJ
Related
I want to construct a HTTP POST request with a body using Go net/http library.
The function I am using to construct the http request is the following: docs
http.NewRequest(method string, url string, body io.Reader)
I came up with 2 solutions, but I am trying to see which one is more idiomatic and extensible to support different body configurations.
Solution #1
bytesObj := []byte(`{"key":"value"}`)
body := bytes.NewBuffer(bytesObj)
Solution #2
bodyMap := map[string]string{"key":"value"}
bodyBytes, _ := json.Marshal(bodyMap)
body := bytes.NewBuffer(bodyBytes)
Ideally, I will move the code to a helper function that way I can customize the construction of the body. The helper function will be something like
func constructBody(someArgument) io.Reader {
return bodyHere
}
If the body is already string, options #1 is more compelling to me.
If you are only working with a key -> value with only string, option #2 is better.
But this will become cumbersome when you have nested struct
But most of the time in my experience we are dealing with struct. I like to make the struct closer to where the http call happened.
func main() {
ctx := context.Background()
body := struct {
Key string `json:"key"`
}{
Key: "value",
}
out, err := json.Marshal(body)
if err != nil {
log.Fatal(err)
}
req, err := http.NewRequest("POST", "http://example.com", bytes.NewBuffer(out))
if err != nil {
log.Fatal(err)
}
req = req.WithContext(ctx)
http.DefaultClient.Do(req)
}
And if the struct is used in multiple places, you can make a package level struct.
To have it more reusable, you could create a jsonReaderFactory, which just takes a few lines of code:
func jsonReaderFactory(in interface{}) (io.Reader, error) {
buf := bytes.NewBuffer(nil)
enc := json.NewEncoder(buf)
err := enc.Encode(in)
if err != nil {
return nil, fmt.Errorf("creating reader: error encoding data: %s", err)
}
return buf, nil
}
Example on playground
If you use the http.FileServer in Go like:
func main() {
port := flag.String("p", "8100", "port to serve on")
directory := flag.String("d", ".", "the directory of static file to host")
flag.Parse()
http.Handle("/", http.FileServer(http.Dir(*directory)))
log.Printf("Serving %s on HTTP port: %s\n", *directory, *port)
log.Fatal(http.ListenAndServe(":"+*port, nil))
}
Then accessing a directory will give you a listing of files. Often this is disabled for web services and instead responds with 404 and I would like this behaviour too.
http.FileServer has no options for this AFAIK and I have seen a proposed way to solve this here https://groups.google.com/forum/#!topic/golang-nuts/bStLPdIVM6w what they do is wrapping the http.FileSystem type and implementing an own Open method. However this doesn't give a 404 when the path is a directory, it just gives a blank page, and it's unclear how to modify it to accomodate this. This is what they do:
type justFilesFilesystem struct {
fs http.FileSystem
}
func (fs justFilesFilesystem) Open(name string) (http.File, error) {
f, err := fs.fs.Open(name)
if err != nil {
return nil, err
}
return neuteredReaddirFile{f}, nil
}
type neuteredReaddirFile struct {
http.File
}
func (f neuteredReaddirFile) Readdir(count int) ([]os.FileInfo, error) {
return nil, nil
}
func main() {
fs := justFilesFilesystem{http.Dir("/tmp/")}
http.ListenAndServe(":8080", http.FileServer(fs))
}
Note: if you make Readdir return nil, os.ErrNotExist then you get a 500 response with "Error reading directory" - not 404.
Any ideas on how to neatly present a 404 and still preserving the feature of automatically finding an index.html if present?
This behavior can be changed if you substitute not a Readdir method, but the Stat.
Please take a look at working code below. It supports serving of index.html files if they are inside of requested directory and returns 404 in case there is no index.html and it is a directory.
package main
import (
"io"
"net/http"
"os"
)
type justFilesFilesystem struct {
fs http.FileSystem
// readDirBatchSize - configuration parameter for `Readdir` func
readDirBatchSize int
}
func (fs justFilesFilesystem) Open(name string) (http.File, error) {
f, err := fs.fs.Open(name)
if err != nil {
return nil, err
}
return neuteredStatFile{File: f, readDirBatchSize: fs.readDirBatchSize}, nil
}
type neuteredStatFile struct {
http.File
readDirBatchSize int
}
func (e neuteredStatFile) Stat() (os.FileInfo, error) {
s, err := e.File.Stat()
if err != nil {
return nil, err
}
if s.IsDir() {
LOOP:
for {
fl, err := e.File.Readdir(e.readDirBatchSize)
switch err {
case io.EOF:
break LOOP
case nil:
for _, f := range fl {
if f.Name() == "index.html" {
return s, err
}
}
default:
return nil, err
}
}
return nil, os.ErrNotExist
}
return s, err
}
func main() {
fs := justFilesFilesystem{fs: http.Dir("/tmp/"), readDirBatchSize: 2}
fss := http.FileServer(fs)
http.ListenAndServe(":8080", fss)
}
I am wondering how I can do something similar to this. I currently have multiple packages with that same structure and functions but they actually retrieve values from multiple APIs. I am also loading in a config that has an array with parameters to use one of those packages per array item.
I am wondering how I can create a variable that uses one of those packages based on the config value. Hopefully this is clear enough. Here is pseudo code that I have written up to explain. Thanks in advance
package main
import (
"errors"
"flag"
"os"
"project/lib"
"project/morelib"
"project/extralib"
"fmt"
"math"
"math/rand"
"time"
)
func stuff(info RunInfo) (err error) {
apiKey:= "stuff1" // actually in the config
apiSecret := "stuff2" // actually in the config
variable := lib.New(apiKey, apiSecret) //returns *Lib struct
//this is where I have to comment out the other libs and uncomment them as needed
// variable := morelib.New(apiKey, apiSecret)
// variable := extralib.New(apiKey, apiSecret)
//trying to switch between libraries like this or in a switch statement
if info.libname == "lib"{
variable = lib.New(apiKey, apiSecret) //.New("", "") returns *Lib struct
}else if info.libname == "morelib"{
variable = morelib.New(apiKey, apiSecret) //.New("", "") returns *MoreLib struct
}else if info.libname == "extralib"{
variable = extralib.New(apiKey, apiSecret) //.New("", "") returns *ExtraLib struct
}else{
err = errors.New("there was an error with the value.....")
return err
}
mystuffs, err := variable.GetBalance("USD")
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("mystuff value: %v", mystuffs.value)
return
}
type RunInfo struct{
libname string
//other stuff
}
func main() {
//load from config with array
config := config.Load()
for i:=0; i<compare; i++{
var runInfo RunInfo
runInfo.libname = config.libname
stuff(runInfo)
}
}
pseudo lib code:
func New(apiKey, apiSecret string) *Lib {
client := NewClient(apiKey, apiSecret)
return &Lib{client}
}
func NewClient(apiKey, apiSecret string) (c *client) {
return &client{apiKey, apiSecret, &http.Client{}, false}
}
type Lib struct {
client *client
}
type client struct {
apiKey string
apiSecret string
httpClient *http.Client
debug bool
}
func (b *Lib) GetBalance(currency string) (balance Balance, err error) {
payload, err := json.Marshal(BalanceParams{Currency: currency})
if err != nil {
return
}
r, err := b.client.do("POST", "GetBalance", string(payload), true)
if err != nil {
return
}
var response jsonResponse
if err = json.Unmarshal(r, &response); err != nil {
return
}
if err = handleErr(response); err != nil {
return
}
err = json.Unmarshal(response.Result, &balance)
return
}
Use and if statement as in the question, a switch statement or a map.
I assume that the type returned by the New function is the following interface:
type GetStuffer interface
GetStuff(string) (Stuff, error)
}
The switch statement is:
var variable GetStuffer
switch info.CompareVal {
case "lib":
variable = lib.New(string1, string2)
case "morelib":
variable = morelib.New(string1, string2)
case "extralib":
variable = extralib.New(string1, string2)
default:
return errors.New("there was an error with the value.....")
}
mystuffs, err := variable.GetMyStuff()
if err != nil {
fmt.Println(err)
return
}
For the map, initialize a package level variable with the map:
var m = map[string]func(string,string) GetStuffer {
"lib": lib.New,
"morelib": morelib.New,
"extralib": extralib.New,
}
and use it like this:
fn := m[info.CompareValue]
if m == nil {
return errors.New("there was an error with the value.....")
}
variable := fn(string1, string2)
mystuffs, err := variable.GetMyStuff()
if err != nil {
fmt.Println(err)
return
}
If the assumption above about the return type is not correct, then there are two options. The first and likely the simplest is to modify New functions to return type GetStuffer. If that's not possible, then write little adaptor functions:
var m = map[string]func(string,string) GetStuffer {
"lib":func(s1, s2 string) GetStuffer { return lib.New(s1, s2) }
"morelib":func(s1, s2 string) GetStuffer { return morelib.New(s1, s2) }
"extralib":func(s1, s2 string) GetStuffer { return extralib.New(s1, s2) }
}
Why don't you define an interface that's only one function? In your example would be
type Stuffer interface {
GetMyStuff(string) (Stuff, error)
}
Then you declare your variable as type Stuffer.
First let's consider the following:
func process(body io.Reader) {
fmt.Printf("body == nil ? %+v\n", body == nil)
}
func main() {
var body *bytes.Buffer
fmt.Printf("body == nil ? %+v\n", body == nil)
process(body)
process(nil)
}
And here's the output:
body == nil ? true
body == nil ? false // Did you get this right?
body == nil ? true
Another example:
type Container struct {
Reader io.Reader
}
func processContainer(container Container) {
fmt.Printf("container.Reader == nil ? %+v\n", container.Reader == nil)
}
func main() {
var body *bytes.Buffer
processContainer(Container{Reader: body})
processContainer(Container{Reader: nil})
}
Output:
container.Reader == nil ? false // Did you get this right?
container.Reader == nil ? true
The explanation for this is at https://golang.org/doc/faq#nil_error.
A naive solution is to make the == nil test just return true if the interface object contains nil value. But this would violate transitivity of ==, as it would assert two objects with nil value but different interface types true under ==.
However, I wonder if there should be an IsNil() method on all interface types, which would solve this issue?
Another example, this line from Go http client, can catch you unexpectedly:
https://github.com/golang/go/blob/master/src/net/http/client.go#L545
So if you call it like this
var body *bytes.Buffer
http.NewRequest(method, path, body)
You'll get a nil pointer exception, even though, by the look of the source code, this shouldn't happen.
Edit
Sorry I referenced the wrong line of the Go http source, now corrected.
But the example still holds.
Edit 2
I've highlighted my question to make it clear what I'm asking.
First read this related question: Hiding nil values, understanding why golang fails here
You can check if the interface value itself is nil by comparing it to nil.
If you want to check if the value wrapped inside a non-nil interface is nil, you can use reflection: reflect.Value.IsNil().
See this modified example:
func process(body io.Reader) {
fmt.Printf("process(): body == nil ? %t\n", body == nil)
if body != nil {
fmt.Println("\tINSIDE IsNil():", reflect.ValueOf(body).IsNil())
}
}
func main() {
var body *bytes.Buffer
fmt.Printf("main(): body == nil ? %t\n", body == nil)
process(body)
process(nil)
process(&bytes.Buffer{})
}
Output (try it on the Go Playground):
main(): body == nil ? true
process(): body == nil ? false
INSIDE IsNil(): true
process(): body == nil ? true
process(): body == nil ? false
INSIDE IsNil(): false
If you want a "unified" IsNil() function which tells if either is nil:
func IsNil(i interface{}) bool {
return i == nil || reflect.ValueOf(i).IsNil()
}
Here's a function that reports if an interface contains any nil. Note that reflect.Value.IsNil() panics if the type doesn't have a nil value, so some checking on the kind must be done before calling it.
func isNil(x interface{}) bool {
v := reflect.ValueOf(x)
switch v.Kind() {
case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.UnsafePointer, reflect.Slice:
return v.IsNil()
default:
return false
}
}
Here's a working example in the playground: https://play.golang.org/p/RHzu3VVj4Zd
The following is clearly based on Paul Hankin's answer, a tad of what icza wrote and the sources of reflect/value.go where func (v Value) IsNil() bool is defined. Do not trust the source, I am a newbie taking advantage of Cunningham's law! I would have just commented but I do not even have 50 points (-:
func isNil(x interface{}) bool {
if x == nil { // nil with no type.
return true
}
v := reflect.ValueOf(x)
switch v.Kind() { // reflect.Invalid for nil
case reflect.Chan, reflect.Func, reflect.Map, // 1st case of v.isNil
reflect.Ptr, reflect.UnsafePointer,
reflect.Interface, reflect.Slice: // 2nd case of v.isNil
return v.IsNil()
default:
return false
}
}
So I have a function getToken()
func getToken() jwt.MapClaims {
tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkYW0iLCJwYXNzd29yZCI6InRlc3QiLCJpYXQiOjE0ODcyMDY2OTIsImV4cCI6MTUxODc2NDI5Mn0.6LQo_gRwXiFBvNIJOwtf9UuxoQMZZ3XNILTnU-46-Zg"
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
}
hmacSampleSecret := []byte("supersecretkittysecret")
return hmacSampleSecret, nil
})
if err != nil {
println("error")
}
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
return claims
} else {
return nil
}
}
Then the corresponding call:
res := getToken()
println(res["username"])
Why is res["username"] equal to two memory addresses (0x2b3c20,0xc420075420)? This should just be a string like adam. I have also tried func getToken() *jwt.MapClaims and return &claims, but this still did not help.
You should try using fmt.Println instead of println. Here's an example of printing a map using println vs fmt.Println
package main
import (
"fmt"
)
func foo() map[string]string {
return map[string]string{
"k": "value",
}
}
func main() {
res := foo()
println("Output from println:", res) // prints pointer address
fmt.Println("Output from fmt.Println: ", res) // prints the map
}
https://play.golang.org/p/gCNqng3KEE
Output:
Output from println: 0x10432200
Output from fmt.Println: map[k:value]