I am trying to setup a bool variable with a default value and update it based on a condition, in Go Lang. The func foo compiles, But the function bar doesn't compile and gives an error "f declared and not used"
There is a related answer - which doesn't explain the next question
What is the correct pattern for this(bar function) in Go?
Here is the code:
package main
import (
"fmt"
"strconv"
)
func foo(m map[string]string) bool {
f := false
if _, exists := m["READWRITE"]; exists {
fmt.Println("Before Updating f : ", f)
f, _ = strconv.ParseBool(m["READWRITE"])
//if err != nil {
// panic(err)
//}
}
fmt.Println("After Updating f : ", f)
return f
}
func bar(m map[string]string) bool {
f := false
if _, exists := m["READWRITE"]; exists {
fmt.Println("Before Updating f : ", f)
f, err := strconv.ParseBool(m["READWRITE"]) // error on this line "f declared and not used"
if err != nil {
panic(err)
}
}
fmt.Println("After Updating f : ", f)
return f
}
func main() {
m := map[string]string{"READWRITE": "true"}
fmt.Println(foo(m))
fmt.Println(bar(m))
}
gives an error "f declared and not used"
f
in your sample is a newly-declared variable. Its scope lies within the if
block, and is different from the one originally declared at the start of your main()
.
Here is a sample commented code that may help clarify (also available as a runnable Go Playground snippet):
package main
import (
"fmt"
)
func main() {
food := "burger" // (1) variable 'food' is declared
fmt.Println("food is", food) // OUTPUT: "burger"
if true {
food := "fries" // (2) a new 'food' variable is a declared here. it shadows the one in (1)
fmt.Println("food is", food) // this accesses the 'food' var from (2). OUTPUT: "fries"
}
fmt.Println("food is", food) // this accesses the variable from (1). OUTPUT: "burger"
}
Hope this helps clarify. Cheers,
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
The if
starts a new block and hence this line is declaring a new variable with name f
.
On the other hand =
operator is an assignment operator and hence the value from the previous scope is modified.
If you want to re-use the same variable, you can declare err
explicitly.
var err error
f, err = strconv.ParseBool(m["READWRITE"])
if err != nil {
panic(err)
}
Context on why I am calling this out: For a person moving to Go from quite a few other languages, this would be an oddity.
I am adding this here - just to demonstrate that it might be useful to use a temp variable explicitly. barNotCorrectYet, has f being updated with the "default false" return from strconv.ParseBool (which would have changed the preset value). So, on cases where we want to ignore bad inputs, it will be useful to assign output to a temp variable, check if no errors were returned and then update the preset value barCorrectHandlingOfTempVariable.
func barNotCorrectYet(m map[string]string) bool {
f := true // preset value of variable
if _, exists := m["READWRITE"]; exists {
var err error
fmt.Println("Before Updating f : ", f)
f, err = strconv.ParseBool(m["READWRITE"])
if err != nil {
// If error, wrong value got updated on f.. and erased preset value
}
}
fmt.Println("[Value could be wrong] After Updating f : ", f)
return f
}
func barCorrectHandlingOfTempVariable(m map[string]string) bool {
f := true // preset value of variable
if _, exists := m["READWRITE"]; exists {
fmt.Println("Before Updating f : ", f)
temp, err := strconv.ParseBool(m["READWRITE"])
if err != nil { // Update only when there are no errors to not affect preset value
f = temp
}
}
fmt.Println("After Updating f : ", f)
return f
}