Go Declare Variable outside vs Declare Variable Inside Loop - go

I am a new in programming. I have two examples code in Go and its about loop using range. This is the first example:
Program A
type Test struct {
Text string
}
func main() {
tests := []Test{
Test{"Test1"},
Test{"Test2"},
}
var a Test
for _, test := range tests {
a = test
fmt.Println(a)
}
}
This is the second example:
Program B
type Test struct {
Text string
}
func main() {
tests := []Test{
Test{"Test1"},
Test{"Test2"},
}
for _, test := range tests {
a := test
fmt.Println(a)
}
}
In the first example 'a' is declared outside the loop, but in the second example 'a' is declared inside the loop. Like in the other programming language, what is the difference between two example program? Is there any optimization difference? Thank you.

The variables have different scopes. It is usually best practice to use the smallest scope possible as in the second example.
There should be no optimization difference.

Related

Golang: Shorthand Variable Declaration inside For loop [duplicate]

I am a new in programming. I have two examples code in Go and its about loop using range. This is the first example:
Program A
type Test struct {
Text string
}
func main() {
tests := []Test{
Test{"Test1"},
Test{"Test2"},
}
var a Test
for _, test := range tests {
a = test
fmt.Println(a)
}
}
This is the second example:
Program B
type Test struct {
Text string
}
func main() {
tests := []Test{
Test{"Test1"},
Test{"Test2"},
}
for _, test := range tests {
a := test
fmt.Println(a)
}
}
In the first example 'a' is declared outside the loop, but in the second example 'a' is declared inside the loop. Like in the other programming language, what is the difference between two example program? Is there any optimization difference? Thank you.
The variables have different scopes. It is usually best practice to use the smallest scope possible as in the second example.
There should be no optimization difference.

Can I get a mixture of := and = in Go if statements? [duplicate]

This code:
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, playground")
var a bool
var b interface{}
b = true
if a, ok := b.(bool); !ok {
fmt.Println("Problem!")
}
}
Yields this error in the golang playground:
tmp/sandbox791966413/main.go:11:10: a declared and not used
tmp/sandbox791966413/main.go:14:21: a declared and not used
This is confusing because of what we read in the short variable declaration golang docs:
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, my questions:
Why can't I redeclare the variable in the code snippet above?
Supposing I really can't, what I'd really like to do is find
a way to populate variables with the output of functions while
checking the error in a more concise way. So is there any way
to improve on the following form for getting a value out of an
error-able function?
var A RealType
if newA, err := SomeFunc(); err != nil {
return err
} else {
A = newA
}
This is happening because you are using the short variable declaration in an if initialization statement, which introduces a new scope.
Rather than this, where a is a new variable that shadows the existing one:
if a, ok := b.(bool); !ok {
fmt.Println("Problem!")
}
you could do this, where a is redeclared:
a, ok := b.(bool)
if !ok {
fmt.Println("Problem!")
}
This works because ok is a new variable, so you can redeclare a and the passage you quoted is in effect.
Similarly, your second code snippet could be written as:
A, err := SomeFunc()
if err != nil {
return err
}
You did redeclare the variable, that is the problem. When you redeclare a variable, it is a different variable. This is known as "shadowing".
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, playground")
// original a.
var a bool
var b interface{}
b = true
// redeclared a here. This is a a'
if a, ok := b.(bool); !ok {
// a' will last until the end of this block
fmt.Println("Problem!")
}
// a' is gone. So using a here would get the original a.
}
As for your second question. That code looks great. I would probably switch it to if err == nil (and swap the if and else blocks). But that is a style thing.
The error raised by the compiler is saying that both declarations of variable a are not being used.
You're actually declaring a twice, when using short declaration in the if condition you're creating a new scope that shadows the previous declaration of the variable.
The actual problem you're facing is that you're never using the variable value which, in Go, is considered a compile time error.
Regarding your second question, I think that the shortest way to get the value and check the error is to do something similar to this:
func main() {
a, ok := someFunction()
if !ok {
fmt.Println("Problem!")
}
}

defining function inside of function

When defining a inner function which utilizes the variables of outer scope, should I pass the variables to the inner function as parameters?
In my example, generate and generate2 both give me same result, is there a reason I should choose any one of them?
The code picks key 1 to generate combinations with key 3,4,5,
then picks key 2 to generate combinations with key 3,4,5.
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, playground")
src := map[int][]string{
1: []string{"1", "11", "111"},
2: []string{"2", "22"},
3: []string{"3"},
4: []string{"4"},
5: []string{"5", "55"},
}
result2 := generate2(src)
fmt.Println(result2)
result := generate(src)
fmt.Println(result)
}
func generate(src map[int][]string) []string {
var combo []string
var add = func(f []string) {
for _, v := range f {
for _, p := range src[3] {
for _, q := range src[4] {
for _, r := range src[5] {
combo = append(combo, v+p+q+r)
}
}
}
}
}
add(src[1])
add(src[2])
return combo
}
func generate2(src map[int][]string) []string {
var combo []string
var add = func(f []string, combo []string, src map[int][]string) []string {
for _, v := range f {
for _, p := range src[3] {
for _, q := range src[4] {
for _, r := range src[5] {
combo = append(combo, v+p+q+r)
}
}
}
}
return combo
}
combo = add(src[1], combo, src)
combo = add(src[2], combo, src)
return combo
}
When defining a inner function which utilizes the variables of outer scope, should I pass the variables to the inner function as parameters?
It depends on what you want to achieve.
What you call "a function inside a function" is actually called "a closure" (and some people call it "lambda").
Closures capture variables from the outer lexical scope, referenced in its body. In Go, this capturing is done "by reference" or "by name" which basically means each time a closure is called it will "see" current values of the variables it closes over, not the values these variables had at the time the closure was created—observe that the program:
package main
import (
"fmt"
)
func main() {
i := 42
fn := func() {
fmt.Println(i)
}
fn()
i = 12
fn()
}
would output
42
12
Conversely, when you pass values as arguments to calls to a closure, each call will see exactly the values passed to it.
I hope you now see that what strategy to pick largely depends on what you want.
Conceptually, you may think of a closure as being an instance of an ad-hoc anonymous struct data type, the fields of which are pointers to the variables the closure closes over, and each call to that closure being analogous to calling some (anonymous, sole) method provided by that type (actually, that's what the compiler usually does behind your back to implement a closure).
Such "method" may have arguments, and whether it should have them, and what should go to the type's fields and what should be that method's arguments can be judged using the usual approach you employ with regular types.
In this context, there is no functional difference between the two functions. As you noticed, local functions have access to local variables without explicitly passing them. In your example you might prefer to use generate1 for easier reading.

Redeclare a variable for convenience in golang?

This code:
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, playground")
var a bool
var b interface{}
b = true
if a, ok := b.(bool); !ok {
fmt.Println("Problem!")
}
}
Yields this error in the golang playground:
tmp/sandbox791966413/main.go:11:10: a declared and not used
tmp/sandbox791966413/main.go:14:21: a declared and not used
This is confusing because of what we read in the short variable declaration golang docs:
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, my questions:
Why can't I redeclare the variable in the code snippet above?
Supposing I really can't, what I'd really like to do is find
a way to populate variables with the output of functions while
checking the error in a more concise way. So is there any way
to improve on the following form for getting a value out of an
error-able function?
var A RealType
if newA, err := SomeFunc(); err != nil {
return err
} else {
A = newA
}
This is happening because you are using the short variable declaration in an if initialization statement, which introduces a new scope.
Rather than this, where a is a new variable that shadows the existing one:
if a, ok := b.(bool); !ok {
fmt.Println("Problem!")
}
you could do this, where a is redeclared:
a, ok := b.(bool)
if !ok {
fmt.Println("Problem!")
}
This works because ok is a new variable, so you can redeclare a and the passage you quoted is in effect.
Similarly, your second code snippet could be written as:
A, err := SomeFunc()
if err != nil {
return err
}
You did redeclare the variable, that is the problem. When you redeclare a variable, it is a different variable. This is known as "shadowing".
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, playground")
// original a.
var a bool
var b interface{}
b = true
// redeclared a here. This is a a'
if a, ok := b.(bool); !ok {
// a' will last until the end of this block
fmt.Println("Problem!")
}
// a' is gone. So using a here would get the original a.
}
As for your second question. That code looks great. I would probably switch it to if err == nil (and swap the if and else blocks). But that is a style thing.
The error raised by the compiler is saying that both declarations of variable a are not being used.
You're actually declaring a twice, when using short declaration in the if condition you're creating a new scope that shadows the previous declaration of the variable.
The actual problem you're facing is that you're never using the variable value which, in Go, is considered a compile time error.
Regarding your second question, I think that the shortest way to get the value and check the error is to do something similar to this:
func main() {
a, ok := someFunction()
if !ok {
fmt.Println("Problem!")
}
}

Code Duplication in Go Type Switches

Just getting started writing Go code and I ran into an interesting problem.
Is there a way to easily iterate over the items in an array that is brought in as an empty interface without code duplication? Consider the following:
function(someArr interface{}){
switch someArr.(type){
case []int :
arr := (someArr).([]int)
for i := range (arr) {
// CODE
}
case []string :
arr := (someArr).([]string)
for i := range (arr) {
// CODE
}
}
}
In this example the code in CODE is exactly the same. However, I cannot take it out of the switch because the type assertion arr would fall out of scope. Similarly, I can't define arr before the switch because I don't know what type it will be. It's possible that this just cannot be done. In that case, what's a better idiom for this kind of thing when I'm, say, parsing JSON with an irregular schema (some arrays of ints, some arrays or strings)?
Your example is not idiomatic Go code, even though the idiomatic one lexically seems violating the DRY principle as well.
The key point to understand is that 'x' is a separate, differently typed variable in each type case:
function(someArr interface{}){
switch x := someArr.(type) {
case []int:
for i := range x {
// CODE
}
case []string:
for i := range x {
// CODE
}
}
}
You can use the reflect package to iterate over arbitrary slices. But implementing the special cases (like []int) explicitly is generally faster and is often done in addition to avoid reflection in common cases.
package main
import "fmt"
import "reflect"
func foo(values interface{}) {
rv := reflect.ValueOf(values)
if rv.Kind() != reflect.Slice {
return
}
n := rv.Len()
for i := 0; i < n; i++ {
value := rv.Index(i).Interface()
fmt.Println(value)
}
}
func main() {
foo([]int{1, 3, 3, 7})
}
Edit: I'm not sure why somebody has down voted the question and my answer, but there are cases where you need to deal with code like that. Even the standard library contains plenty of it, take a look at "fmt", "gob", "json", "xml" and "template" for example. The questioner might face a similar problem.

Resources