Undefined variable golang [duplicate] - go

This question already has answers here:
Variable scope inside if statements
(2 answers)
Closed 4 years ago.
Can someone tell me why num is undefined :: Here is go playground link also you can check this code here:
https://play.golang.org/p/zR9tuVTJmx-
package main
import "fmt"
func main() {
if 7%2 == 0 {
num := "first"
} else {
num := "second"
}
fmt.Println(num)
}

That's something related to lexical scoping, look over here for an introduction
Basically any variable within {}curly braces is considered as new variable, within that block.
so In the above program you have created two new variables.
Block is something like enclosing a around a variable.
If you are outside a block, you cannot see it. you need to be inside the block in order to see it.
package main
import "fmt"
func main() {
if 7%2 == 0 {
// you are declaring a new variable,
num := "first"
//this variable is not visible beyond this point
} else {
//you are declaring a new variable,
num := "second"
//this variable is not visible beyond this point
}
// you are trying to access a variable, which is declared in someother block,
// which is not valid, so undefined.
fmt.Println(num)
}
What you are looking for is this:
package main
import "fmt"
func main() {
num := ""
if 7%2 == 0 {
//num is accessible in any other blocks below it
num = "first"
} else {
num = "second"
}
//num is accessible here as well, because we are within the main block
fmt.Println(num)
}

Related

Short declaration in Go

I'm learning Go and I don't understand how the code is allowing me to redeclare the same variable "phones". I thought you can only short-declare a variable once inside a function scope and then you can redeclare that variable only when you are declaring a new variable with it. But with the code below, I'm able to short-declare "phones" twice without declaring a new variable in the second short-declare statement.
package main
import "fmt"
func main() {
phones := map[string]string{
"bowen": "202-555-0179",
"dulin": "03.37.77.63.06",
"greco": "03489940240",
}
multiPhones := map[string][]string{
"bowen": {"202-555-0179"},
"dulin": {"03.37.77.63.06", "03.37.70.50.05", "02.20.40.10.04"},
"greco": {"03489940240", "03489900120"},
}
fmt.Println(phones)
who, phone := "greco", "N/A"
if phones := multiPhones[who]; len(phones) >= 2 {
fmt.Println(phones)
phone = phones[1]
}
fmt.Printf("%s's 2nd phone number: %s\n", who, phone)
}
I thought you can only short-declare a variable once inside a function scope
No, this is wrong. Go is block scoped, not function scoped.
Each variable can be declared once per block and if starts a new block.
(Note that this holds for any type of declaration, be it short or long.)
Go does not allow redefined variables in the same scope.
The code you have contains variables in two different scopes.
This is allowed in Go. It is not a problem.
Your code is similar to:
func main() {
name := "adam"
if name := true; name != false { // the var name here is in if scope.
fmt.Println("name in if scope is :", name)
}
fmt.Println("name out if scope is : ", name)
// name := "jawad" this is error. redifined in same scope not allowed.
}

Calling a variable from another function in go

I know that variables are pass by value in go. However, I want to call a variable that in inside a func outside this function. Let me give you an example:
package main
import (
"fmt"
)
func Smile(){
A := 5
}
func main() {
fmt.Println(A)
}
This gives me undefine A.
what is the best way to pass A ? Should I use a pointer? How do I do that?
It's not possible to print the value of the A variable declared in the Smile() function from main().
And the main reason for that is that the variable A only exists if code execution enters the Smile() function, more precisely reaches the A variable declaration. In your example this never happens.
And even if in some other example this happens (e.g. Smile() is called), an application may have multiple goroutines, and multiple of them may be executing Smile() at the same time, resulting in the app having multiple A variables, independent from each other. In this situation, which would A in main() refer to?
Go is lexically scoped using blocks. This means the variable A declared inside Smile() is only accessible from Smile(), the main() function cannot refer to it. If you need such "sharing", you must define A outside of Smile(). If both Smile() and main() needs to access it, you have to make it either a global variable, or you have to pass it to the functions that need it.
Making it a global variable, this is how it could look like:
var a int
func smile() {
a = 5
fmt.Println("a in smile():", a)
}
func main() {
smile()
fmt.Println("a in main():", a)
}
This outputs (try it on the Go Playground):
a in smile(): 5
a in main(): 5
Declaring it local in main() and passing it to smile(), this is how it could look like:
func smile(a int) {
fmt.Println("a in smile():", a)
}
func main() {
a := 5
fmt.Println("a in main():", a)
smile(a)
}
Output (try it on the Go Playground):
a in main(): 5
a in smile(): 5
The best way is, https://godoc.org/golang.org/x/tools/go/pointer
Pointers
Ex:
func getCar() {
car := Vehicles.Car{}
setModel(&car)
// model ("BMW") will be available here
}
func setModel(car *Vehicles.Car) {
car.Model = "BMW"
}

Name of current function [duplicate]

This question already has answers here:
How to get the current function name
(4 answers)
Closed 4 years ago.
Is there a way to include the name of the current function I am in? I'd like to include it in my debug logs rather than hard coding the func name which is a pain after a while.
Thanks.
You can do this using runtime.Callers
package main
import (
"fmt"
"runtime"
)
func printFuncName() {
fpcs := make([]uintptr, 1)
// Skip 2 levels to get the caller
n := runtime.Callers(2, fpcs)
if n == 0 {
fmt.Println("MSG: NO CALLER")
}
caller := runtime.FuncForPC(fpcs[0] - 1)
if caller == nil {
fmt.Println("MSG CALLER WAS NIL")
}
// Print the name of the function
fmt.Println(caller.Name())
}
func foo() {
printFuncName()
}
func main() {
foo()
}
Outputs (package.function)
main.foo

Value assigned and not used in if statement

I wrote an example of the problem I'm seeing in go playground:
https://play.golang.org/p/rPCqAC56Ff
It's pretty self evident, but I'm declaring a variable outside of an if statement, setting variable in if and then using outside of if.
The question is simple, why doesn't this work?
package main
import (
"fmt"
"os"
)
func main() {
var foo string
if true {
foo = "foo"
} else {
foo, found := os.LookupEnv("GOPATH")
if !found {
fmt.Printf("who cares.\n")
}
}
println(foo)
}
You're creating a new variable foo in if block with :=
foo, found := os.LookupEnv("GOPATH")
Check blocks and the scoping rules.
The correct code:
package main
import (
"fmt"
"os"
)
func main() {
var foo string
var found bool
if true {
foo = "foo"
} else {
foo, found = os.LookupEnv("GOPATH")
if !found {
fmt.Printf("who cares.\n")
}
}
println(foo)
}
From Go documentation:
An identifier declared in a block may be redeclared in an inner block.
While the identifier of the inner declaration is in scope, it denotes
the entity declared by the inner declaration.
:= in the else block redeclares foo, so that foo now refers to a whole new variable with the same name, a variable which is never used. Even if we somehow reached the else block, the println(foo) at last line wouldn't print our $GOPATH as that's stored to the other foo variable (or was until the whole variable went out of scope)
Correct code would be:
func main() {
var foo string
if true {
foo = "foo"
} else {
var found bool
foo, found = os.LookupEnv("GOPATH")
if !found {
fmt.Printf("who cares.\n")
}
}
println(foo)
}
It's easy to get confused since this code works fine even though foo is redeclared before it used:
func main() {
var foo string
foo = "foo"
foo, found := os.LookupEnv("GOPATH")
if !found {
fmt.Printf("who cares.\n")
}
println(foo)
}
What's happening here is that there's also another, different kind of legal redeclaration in Go:
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.
So in this other kind of redeclaration, no new foo variable is actually created and it works just like assignment to foo.

Why the shorthand syntax to declare/init variables?

Is there a difference between these 2 styles of variable declaration/initialization?
package main
import "fmt"
func main() {
var a = "I am a string" // Declare + init (infer)
fmt.Println(a)
b := "I am a string" // Declare + init (shorthand)
fmt.Println(b)
}
I fail to see the added value of the shorthand syntax, and inclined to use the "var" statement for consistency throughout my code.
I always try to use the := syntax. The benefit is huge when you need to Refactor code.
You are not binding the name of the variable to any particular type and any time you change the right hand side's type the variable would automatically infer the new type.
I only use var when necessary, like:
1) global variables
2) if statement like:
var err error
if x == nil {
err = errors.New("x is nil")
} else if y == nil {
err = errors.New("y is nil")
}
...

Resources