your Question has 2 parts:
first part:
= is just assignment
:= is define and assign for new vars(at least one new var) inside the function block(not global), working sample:
package mainimport ("fmt")func main() { var u1 uint32 //declare a variable and init with 0 u1 = 32 //assign its value var u2 uint32 = 32 //declare a variable and assign its value at once //declare a new variable with defining data type: u3 := uint32(32) //inside the function block this is equal to: var u3 uint32 = 32 fmt.Println(u1, u2, u3) //32 32 32 //u3 := 20//err: no new variables on left side of := u3 = 20 fmt.Println(u1, u2, u3) //32 32 20 u3, str4 := 100, "str" // at least one new var fmt.Println(u1, u2, u3, str4) //32 32 100 str}
second part:
An identifier declared in a block may be redeclared in an inner block.
Here 4 different working samples for Variable scoping and shadowing:
simple way to limit variables scope:
package mainimport "fmt"func main() { i := 1 j := 2 //new scope : { i := "hi" //new local var j++ fmt.Println(i, j) //hi 3 } fmt.Println(i, j) //1 3}
limit variable scope using function calls:
package mainimport "fmt"func fun(i int, j *int) { i++ //+nice: use as local var without side effect *j++ //+nice: intentionally use as global var fmt.Println(i, *j) //11 21}func main() { i := 10 //scope: main j := 20 fun(i, &j) fmt.Println(i, j) //10 21}
using short-hand assignment inside statements:
package mainimport "fmt"func main() { i := 10 //scope: main j := 4 for i := 'a'; i < 'b'; i++ { fmt.Println(i, j) //97 4 } fmt.Println(i, j) //10 4 if i := "test"; len(i) == j { fmt.Println(i, j) // i= test , j= 4 } else { fmt.Println(i, j) //test 40 } fmt.Println(i, j) //10 4}
shadowing global vars:
package mainimport "fmt"var i int = 1 //globalfunc main() { j := 2 fmt.Println(i, j) //1 2 i := 10 //Shadowing global var fmt.Println(i, j) //10 2 fun(i, j) //10 2}func fun(i, j int) { //i := 100 //no new variables on left side of := fmt.Println(i, j) //10 2}