go/*
standard packages.)
{}
encloses a local block. However, some local blocks aren't enclosed within {}
, such blocks are called implicit local blocks. The local blocks enclosed in {}
are called explicit local blocks. The {}
in composite literals and type definitions don't form local blocks.
if
, switch
or for
keyword is followed by two nested local blocks. One is implicit, the other is explicit. The explicit one is nested in the implicit one. If such a keyword is followed by a short variable declaration, then the variables are declared in the implicit block.
else
keyword is followed by one explicit or implicit block, which is nested in the implicit block following its if
counterpart keyword. If the else
keyword is followed by another if
keyword, then the code block following the else
keyword can be implicit, otherwise, the code block must be explicit.
select
keyword is followed by one explicit block.
case
and default
keyword is followed by one implicit block, which is nested in the explicit block following its corresponding switch
or select
keyword.
go/*
standard packages.)
go/*
standard packages.)
break
, continue
, and goto
statements.
the universe block | package blocks | file blocks | local blocks | |
---|---|---|---|---|
predeclared (built-in elements) (1) |
Yes
|
|
|
|
package imports |
|
|
Yes
|
|
defined types and type alias (non-builtin) |
|
Yes
|
Yes
|
Yes
|
named constants (non-builtin) |
|
Yes
|
Yes
|
Yes
|
variables (non-builtin) (2) |
|
Yes
|
Yes
|
Yes
|
functions (non-builtin) |
|
Yes
|
Yes
|
|
variables (non-builtin) (2) |
|
|
|
Yes
|
builtin
standard package.if
, switch
or for
keyword can be closely followed by a short variable declaration.
case
keyword in a select
control flow can be closely followed by a short variable declaration.
go/*
standard packages think file code blocks can only contain package import declarations.)
iota
is only visible in constant declarations.)
package main
func main() {
// var v int = v // error: v is undefined
// const C int = C // error: C is undefined
/*
type T = struct {
*T // error: T uses <T>
x []T // error: T uses <T>
}
*/
// Following type definitions are all valid.
type T struct {
*T
x []T
}
type A [5]*A
type S []S
type M map[int]M
type F func(F) F
type Ch chan Ch
type P *P
// ...
var p P
p = &p
p = ***********************p
***********************p = p
var s = make(S, 3)
s[0] = s
s = s[0][0][0][0][0][0][0][0]
var m = M{}
m[1] = m
m = m[1][1][1][1][1][1][1][1]
}
fmt.Print(s)
and call fmt.Print(m)
both panic (for stack overflow).
package main
// Here the two identifiers at each line are the
// same one. The right ones are both not the
// predeclared identifiers. Instead, they are
// same as respective left one. So the two
// lines both fail to compile.
/*
const iota = iota // error: constant definition loop
var true = true // error: typechecking loop
*/
var a = b // can reference variables declared later
var b = 123
func main() {
// The identifiers at the right side in the
// next two lines are the predeclared ones.
const iota = iota // ok
var true = true // ok
_ = true
// The following lines fail to compile, for
// c references a later declared variable d.
/*
var c = d
var d = 123
_ = c
*/
}
x
. A x
declared in a deeper block shadows the x
s declared in shallower blocks.
package main
import "fmt"
var p0, p1, p2, p3, p4, p5 *int
var x = 9999 // x#0
func main() {
p0 = &x
var x = 888 // x#1
p1 = &x
for x := 70; x < 77; x++ { // x#2
p2 = &x
x := x - 70 // // x#3
p3 = &x
if x := x - 3; x > 0 { // x#4
p4 = &x
x := -x // x#5
p5 = &x
}
}
// 9999 888 77 6 3 -3
fmt.Println(*p0, *p1, *p2, *p3, *p4, *p5)
}
Sheep Goat
instead of Sheep Sheep
. Please read the comments for explanations.
package main
import "fmt"
var f = func(b bool) {
fmt.Print("Goat")
}
func main() {
var f = func(b bool) {
fmt.Print("Sheep")
if b {
fmt.Print(" ")
f(!b) // The f is the package-level f.
}
}
f(true) // The f is the local f.
}
Sheep Sheep
.
func main() {
var f func(b bool)
f = func(b bool) {
fmt.Print("Sheep")
if b {
fmt.Print(" ")
f(!b) // The f is also the local f now.
}
}
f(true)
}
package main
import "fmt"
import "strconv"
func parseInt(s string) (int, error) {
n, err := strconv.Atoi(s)
if err != nil {
// Some new gophers may think err is an
// already declared variable in the following
// short variable declaration. However, both
// b and err are new declared here actually.
// The new declared err variable shadows the
// err variable declared above.
b, err := strconv.ParseBool(s)
if err != nil {
return 0, err
}
// If execution goes here, some new gophers
// might expect a nil error will be returned.
// But in fact, the outer non-nil error will
// be returned instead, for the scope of the
// inner err variable ends at the end of the
// outer if-clause.
if b {
n = 1
}
}
return n, err
}
func main() {
fmt.Println(parseInt("TRUE"))
}
1 strconv.Atoi: parsing "TRUE": invalid syntax
int
, bool
, string
, len
, cap
, nil
, etc. They are just predeclared (built-in) identifiers. These predeclared identifiers are declared in the universe block, so custom declared identifiers can shadow them. Here is a weird example in which many predeclared identifiers are shadowed. Its compiles and runs okay.
package main
import (
"fmt"
)
// Shadows the built-in function identifier "len".
const len = 3
// Shadows the built-in const identifier "true".
var true = 0
// Shadows the built-in variable identifier "nil".
type nil struct {}
// Shadows the built-in type identifier "int".
func int(){}
func main() {
fmt.Println("a weird program")
var output = fmt.Println
// Shadows the package import "fmt".
var fmt = [len]nil{{}, {}, {}}
// Sorry, "len" is a constant.
// var n = len(fmt)
// Use the built-in cap function instead, :(
var n = cap(fmt)
// The "for" keyword is followed by one
// implicit local code block and one explicit
// local code block. The iteration variable
// "true" shadows the package-level variable
// "true" declared above.
for true := 0; true < n; true++ {
// Shadows the built-in const "false".
var false = fmt[true]
// The new declared "true" variable
// shadows the iteration variable "true".
var true = true+1
// Sorry, "fmt" is an array, not a package.
// fmt.Println(true, false)
output(true, false)
}
}
a weird program 1 {} 2 {} 3 {}
The Go 101 project is hosted on Github. Welcome to improve Go 101 articles by submitting corrections for all kinds of mistakes, such as typos, grammar errors, wording inaccuracies, description flaws, code bugs and broken links.
If you would like to learn some Go details and facts every serveral days, please follow Go 101's official Twitter account @zigo_101.
reflect
standard package.sync
standard package.sync/atomic
standard package.