This is the ninth day of my participation in the August More text Challenge. For details, see: August More Text Challenge
This article focuses on sharing scopes in the GO language. The relevant content of the package has been shared in the previous article, so I have not sorted out the relevant article, if you need to know, click here. It contains the package definition, import, initialization and other related content
scope
A declaration associates a name with a program entity, such as a function or a variable. The scope of a declaration is the section of code in which the name is declared when the declaration is used. Do not confuse scope with lifecycle. The scope of a declaration is the area where the declaration appears in the program text and is a compile-time attribute. The life cycle of a variable is the start and end time at which the variable can be referenced by other parts of the program during execution. It is a runtime property
Grammar block
A block is a sequence of statements surrounded by curly braces, such as the body of a loop or function. Variables declared inside a syntax block are not visible outside the block. The block surrounds the declaration and determines its visibility
Lexical chunks
The concept of a block is generalized to other declaration code that is not explicitly contained in braces and is collectively referred to as a lexical block. Contains the full source code of the lexical block, called global fast
Every package, every file, every for, if, and switch statement, and every condition in the switch and SELECT statements, is written in a lexical block. Blocks of code explicitly written in braces are also called lexical blocks
The lexical block of a declaration determines the scope of the declaration. Built-in types, functions, or constants like int, len, and true are declared in the global fast and visible to the entire program. Declarations at the package level can be referenced by any file in the same package. Imported packages are file level, so they can be referenced in the same file, but cannot be referenced in other files in the same package without another import statement. Many declarations are local and can only be referenced within the same function or within only part of the function
The scope of the control-flow label (the label used by break, continue, and goto) is the entire outer layer of functions. A program can contain multiple declarations of the same name, provided they are in different lexical blocks. When the compiler encounters a reference to a name, it looks for its declaration from the innermost enclosing lexical block to the global fast. If it is not found, it will declare an “undeclared name” error. If this declaration exists on both the inner and outer blocks, the inner block will be found first. In this case, the inner declaration overwrites the outer declaration, making it inaccessible
Func f() {} var g = "g" func main() {f := "f" fmt.println (f)//"f" local variable f overwrite package-level function f fmt.println (g)//"g" package-level variable FMT.Println(h)// Compile error, undefined}Copy the code
The sample
In functions, lexical blocks can be deeply nested, so one local variable declaration may override another. Many lexical blocks use control-flow structural artifacts such as if statements and for loops. In the example below, there are three different variable declarations called x because each of them appears in a different lexical block
func main() { x := "hello!" for i := 0; i< len(x); i++ { x := x[i] if x ! = '! '{x = x +' A '-' A 'FMT) Printf (" % c ", x) / / HELLO (A letter) each iteration}}}Copy the code
As mentioned above, not all lexical blocks correspond to explicit bracketed sequences of statements; some lexical blocks are implicit. The for loop creates two lexical blocks: an explicit block that is the body of the loop itself, and an implicit block that contains a closed structure containing variables declared in the initialization statement, such as variable I. The scope of variables declared in an implicit block includes conditions, postposition statements (i++), and the for body itself
In this example, there are three variables named x, each declared in a different lexical block: one in the body of the function, one in the for block, and one in the body of the loop. But only two blocks are explicit:
Func main () {x: = "hello" for _, x: x = the range {x = x + 'A' - 'A' FMT) Printf (" % c ", x) / / hello (A letter) each iteration}}Copy the code
Like the for loop, the if and switch statements create implicit lexical blocks in addition to their own body blocks. The if-else chain in the following example shows the scope of x and y
if x := f(); x==0 { fmt.Println(x) } else if y := g(x); Println(x, y)} else {fmt.println (x, y)} fmt.println (x, y)} fmt.println (x, yCopy the code
The second if statement is nested in the first, so the variables declared in the initialization part of the first statement are visible in the second statement. The same rule applies to switch statements: there is one block for a condition and one block for each case body
if f, err := os.Open(fname); err ! = nil {// compile error, f not used return err} f.close ()// compile error, f not defined f.close ()// compile error, f not definedCopy the code
F is scoped as an if statement, so it cannot be accessed by the following statement, and the compiler will report an error. (Depending on the compiler, you may also receive other errors: the local variable f was not used. (In Go, if a variable is defined but not used, it will fail compilation.)
In these cases, you usually declare f before the condition is determined, making it accessible after the if statement
f, err := os.Open(fname) if err ! = nil {return err} f.stat () f.close () or if f, err := os.open (fname); err ! = nil { return err } else { f.Stat() f.Close() }Copy the code
The usual Go approach is to handle the error in the if block and then return so that the path to successful execution is not fragmented
reference
Go Programming Language — Alan A. A. Donovan
Go Language Learning Notes — Rain Marks