err value disappearing outside of if statement - variables

I have the code below:
if err == nil {
body, err := ioutil.ReadAll(response.Body)
if err == nil {
dataMap := &models.UserResponse{}
json.Unmarshal(body, &dataMap)
if dataMap.User == (models.UserId{}) {
err = fmt.Errorf("unauthorized")
fmt.Println(err) // when unathorized, prints unauthorized
}
}
}
fmt.Println(err) // always prints nil
The Println inside if dataMap.User ... prints "unauthorized", whereas the last Println always prints nil.
I have no idea why it happens, err is declared via var err error at the beginning of this function.

The cause is detailed in Spec: Short variable declaration:
Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block (or the parameter lists if the block is the function body) with the same type, and at least one of the non-blank variables is new. As a consequence, redeclaration can only appear in a multi-variable short declaration. Redeclaration does not introduce a new variable; it just assigns a new value to the original.
When using short variable declaration with multiple variables where one already exists, assignment will only happen to the existing variable if it was declared in the same block. Since in your case err variable existed before the if block, a new err variable will be created inside the if block, which has nothing to do with the "outsider" err variable (other than sharing its name). The outer err will be shadowed in the if block after the short variable declaration.
So what happens is that inside the if, you create a new err variable, and you assign a value to that, and you print that.
After the if statement, you will print the outer err variable whose value was not changed inside the if block, so it remains nil.
See this example:
var err error
fmt.Println("outside:", err) // nil
{
// A new err variable, shadows the outer:
i, err := strconv.Atoi("a")
fmt.Println("inside:", i, err) // 0 strconv.Aoti: parsing "a": invalid syntax
}
fmt.Println("outside:", err) // nil, because this was never changed
// Now this will change the "outer" err:
j, err := strconv.Atoi("a")
fmt.Println("outside:", j, err) // 0 strconv.Aoti: parsing "a": invalid syntax
Output (try it on the Go Playground):
outside: <nil>
inside: 0 strconv.Atoi: parsing "a": invalid syntax
outside: <nil>
outside: 0 strconv.Atoi: parsing "a": invalid syntax
If you want to use (assign to) the "outer" variable when also creating new variable(s), you can't use short variable declaration in a "nested" block but only simple assignment, in which case you also have to declare the other variables a priori, like in this example:
if err == nil {
var body []byte
body, err = ioutil.ReadAll(response.Body)
// ... rest...
}
See related questions:
Why it is possible to redefine err in multiple return statement in Go
Why there are two ways of declaring variables in Go, what's the difference and which to use?

You have created err inside block but you are printing same outside of block. Declare error outside of block and initialize it anywhere inside that will fetch the value when printing.
var err error
fmt.Println(err) // always prints nil

Related

sql golang invalid memory address or nil pointer dereference when do query

i am trying to insert data after the connection, when i command the logic of INSERT... i was able to connect to the database, but when i uncommand them , i got error
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x40f8e2a]
here is my function :
func Connect() (*sql.DB, error) {
db, err := sql.Open("postgres", os.Getenv("PG_URL"))
if err != nil {
return nil, err
}
defer db.Close()
stmt, _ := db.Prepare("INSERT INTO users(name, email, password) VALUES(?,?,?)")
res, err := stmt.Exec("test", "test#mail.com", "12344")
if err != nil{
panic(err.Error())
}
fmt.Println(res)
fmt.Println("Successfully connected!")
return db, nil
}
I have tried to do the same thing also like this article go sql
and have the same issue
do I wrong implement this?
I bet a dollar/euro/frank that the NPE is on the line executing the prepared statement and that if you check the only error you ignored it won't be nil and it will tell you what's wrong.
I had the same problem with sqlite.
As Ivaylo Novakov described in his answer I had to log the err of the prepare statement (which i ignored like you before stmt, _)
For me it was running okay as long as i was developing but when I created my final binary i forgot to enable cgo).
The err got the hint:
Binary was compiled with 'CGO_ENABLED=0', go-sqlite3 requires cgo to work. This is a stub

How do I create a variable in go only if a condition is true?

If I create a variable inside an if block, I can't use it later on. If I create a variable before the if block and the if block evaluates to false, I get a "variable created and not used" error.
I'm certain that this is by design and I'm trying to do something I shouldn't, but the logic behind what I'm trying to do makes sense to me. If there is page info in the url, I want to use it in a sql statement later on, but if there isn't page info in the url, then I don't need those variables.
http://pastebin.com/QqwpdM1d
Edit: here's the code:
var pageID string
var offset int
if len(r.URL.Path) > len("/page/") {
pageID := r.URL.Path[len("/page/"):]
offset, err := strconv.Atoi(pageID)
if err != nil {
log.Fatal(err)
}
}
conn := "..."
db, err := sql.Open("mysql", conn)
defer db.Close()
if err != nil {
log.Fatal(err)
}
var rows *sql.Rows
if offset != 0 {
// ...
}
If you declare a variable before an if statement and you use it inside the if block, it doesn't matter what the condition evaluates to, it is not a compile time error.
The error in you case is that you don't use the declared variable inside the if block. Your code:
var pageID string
var offset int
if len(r.URL.Path) > len("/page/") {
pageID := r.URL.Path[len("/page/"):]
offset, err := strconv.Atoi(pageID)
if err != nil {
log.Fatal(err)
}
}
Inside the if you are not assigning to the previously declared pageID, but you are using short variable declaration := which creates a new variable, shadowing the one created in the outer block, and it is in effect only at the end of the if block (its scope ends at the end of the innermost containing block).
Solution is (what you most likely wanted to) simply use assignment = (which assigns value to the existing variable):
pageID = r.URL.Path[len("/page/"):]
To make it understand, see this example:
i := 1
fmt.Println("Outer:", i)
{
i := 2 // Short var decl: creates a new i, shadowing the outer
fmt.Println("Inner:", i)
}
fmt.Println("Outer again:", i)
Output (try it on the Go Playground):
Outer: 1
Inner: 2
Outer again: 1

mismatched types *string and string

I am attempting to run a conditional to basically see if the object is empty but I keep getting (similar variations) of this error:
invalid operation: release.Name == "" (mismatched types *string and string)
Here is the code that is dying:
import (
"github.com/google/go-github/github"
)
func TestLatestTag(user, project string) {
var client *github.Client
client = github.NewClient(nil)
releases, _, err := client.Repositories.ListTags(user, project, nil)
var release github.RepositoryTag
if err != nil {
fmt.Println("Error")
} else {
if release.Name == "" {
fmt.Println("None")
} else {
fmt.Println(releases[0])
}
}
}
If I change the if statement to *release.Name == "" as the error suggests I get a different error, which I don't really understand:
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0x26fd]
goroutine 1 [running]:
I'm sure there is any easy way to do this but I am not very familiar with handling objects/structs
From the error message it looks like you are trying to compare a string pointer (*string) to an actual string.
release.Name is a *string (a pointer to a string value)
"" is a string (is a string value)
They are two different types. So you can't compare them.
What you probably want to do instead is release.Name == nil
When a pointer that references to nothing (equals to nil) is tried to be dereferenced you get that second error. So in your case *release.Name panics because infact release.Name is nil
var release github.RepositoryTag
You never assign any value to that var. That's why *release.Name gives you a "runtime error": release.Name is a nil pointer
As per your code you have declared var release github.RepositoryTag, but you have not initialized it.
In structure RepositoryTag, Name is declared as *string which is a pointer and in case of release.Name == "", string comparison is attempted which is incorrect hence "mismatched types *string and string" error.
In case of *release.Name == "", since release is not yet initialized, it is complaining "invalid memory address or nil pointer dereference"
You need to do two things, 1st initialize, release and second, check release.Name = nil.

Errors are values (blog) - is logically same?

I just read the blog written by Rob Pike. I have a small question regarding this and may be I can be wrong too but would still like to get feedback and understand properly the Go.
In the blog there was a snippet code (which actually was written by #jxck_)
_, err = fd.Write(p0[a:b])
if err != nil {
return err
}
_, err = fd.Write(p1[c:d])
if err != nil {
return err
}
_, err = fd.Write(p2[e:f])
if err != nil {
return err
}
// and so on
a) As per my understanding the above code will return if error occurred at fd.Write(p0[a:b]), and will never execute fd.Write(p1[c:d]) , right?
And Rob suggested to write something like this
var err error
write := func(buf []byte) {
if err != nil {
return
}
_, err = w.Write(buf)
}
write(p0[a:b])
write(p1[c:d])
write(p2[e:f])
// and so on
if err != nil {
return err
}
b) Based on the above, looks like the error will return from the sub function. So this means if the error occurs at write(p0[a:b]) then still it will execute write(p1[c:d]), right? So this means logically both are not same, right?
Anybody explain.
No, they are the same. If an error occurs at fd.Write(p0[a:b]), the err variable will hold its value.
Now if you call write(p1[c:d]), then the write() func will first check if err != nil but since it already stores the error which occured in the previous call, it will return immediately and will not execute further code.
a) Yes, you are correct. If the error occures in the first write, it will return.
b) No. The write in this example is a closure. The err inside of it is the same as in the outer scope. So if the first write fails, the other will simply return, because the outer err is not nil anymore.

golang upload file err runtime error index out of range

I've put together a golang func that takes an uploaded file and saves it to folder.
Just before os.Create() I am getting the following error :
http: panic serving [::1]:64373: runtime error: index out of range
My golang function is:
func webUploadHandler(w http.ResponseWriter, r *http.Request) {
file, header, err := r.FormFile("file") // the FormFile function takes in the POST input id file
if err != nil {
fmt.Fprintln(w, err)
return
}
defer file.Close()
// My error comes here
messageId := r.URL.Query()["id"][0]
out, err := os.Create("./upload/" + messageId + ".mp3")
if err != nil {
fmt.Fprintf(w, "Unable to create the file for writing. Check your write access privilege")
return
}
defer out.Close()
// write the content from POST to the file
_, err = io.Copy(out, file)
if err != nil {
fmt.Fprintln(w, err)
}
fmt.Fprintf(w,"File uploaded successfully : ")
fmt.Fprintf(w, header.Filename)
}
any ideas? much appreciate
You should at least check if r.URL.Query()["id"] has actually one element.
If len(r.URL.Query()["id"]), you could consider not accessing the index 0.
Easier, Ainar-G suggests in the comments to use the Get() method
Get gets the first value associated with the given key.
If there are no values associated with the key, Get returns the empty string.
To access multiple values, use the map directly.