Go Variables: Difference between revisions
(→Naming) |
|||
(43 intermediate revisions by the same user not shown) | |||
Line 4: | Line 4: | ||
=Overview= | =Overview= | ||
Variables are names associated with memory locations that store values. Variable name rules are described in the [[#Naming|Naming]] section. | Variables are names associated with memory locations that store values. Variable name rules are described in the [[#Naming|Naming]] section. The set of permissible values is determined by the variable's [[Go_Language#Type|type]]. Each variable has a type. Because Go is a [[Programming_Languages_Concepts#Static_Typing_vs_Dynamic_Typing|statically typed language]], the type associate with a variable may not change after the declaration. Each variable defined in Go occupies a unique memory location. It is not possible to have two variables that share the same storage location. It is possible to have two variable that point to the same storage location, in case of [[Pointers_in_Go#Overview|pointer variables]], but this is not the same thing as sharing the same storage location. In other words, Go has [[#Reference_Variables|no reference variables]]. The value of a variable can change at runtime, unlike a <code>[[Go_Constants#Overview|const]]</code>'s. | ||
=<span id='Variable_Names'></span><span id='Idiomatic_Variable_Naming_Conventions'></span>Naming= | =<span id='Variable_Names'></span><span id='Idiomatic_Variable_Naming_Conventions'></span>Naming= | ||
The names of [[ | The names of [[#Overview|variable]] identifiers in Go follow [[Go_Style#Naming|general naming conventions for identifiers]]. | ||
Variable names should be short rather than long. The closer to declaration a name is used, the shorter it should be. Conversely, the farther away from the declaration you use it, the longer the name should be. Long variable names obscure what the code does. Longer names may help in long functions, or functions with many local variable, but often this just means you should refactor. | Variable names should be short rather than long. The closer to declaration a name is used, the shorter it should be. Conversely, the farther away from the declaration you use it, the longer the name should be. Long variable names obscure what the code does. Longer names may help in long functions, or functions with many local variable, but often this just means you should refactor. | ||
Line 24: | Line 24: | ||
=<span id='Reference_Variables'></span><span id='Reference_Variable'></span>(No) Reference Variables= | =<span id='Reference_Variables'></span><span id='Reference_Variable'></span>(No) Reference Variables= | ||
Go does not have [[Variables,_Parameters,_Arguments#Reference|reference variables]]. Each variable defined in Go occupies a unique memory location, which contains the value of the variable. [[Go_Maps#Overview| | Go does not have [[Variables,_Parameters,_Arguments#Reference|reference variables]]. Each variable defined in Go occupies a unique memory location, which contains the value of the variable. [[Go_Arrays#Overview|Arrays]], [[Go_Slices#Overview|slices]], [[Go_Maps#Overview|maps]], [[Go_Channels#Overview|channels]], etc. variables are all values, not references. As such, there is no pass-by-reference in Go, everything is passed by value. To achieve behavior similar to pass-by-reference, use pointers. This is explained here: {{Internal|Go_Functions#Pass-by-value_vs._pass-by-pointer_vs._pass-by-reference|Pass by Value vs. Pass by Reference vs. Pass by Pointer in Go}} | ||
=<span id='Variable_Declaration'></span>Variable Declaration and Initialization= | |||
In Go variables must be explicitly declared to be used. There is a "[[#Long|long]]" declaration statement that uses the <code>var</code> keyword and a "[[#Short_Variable_Declaration|short]]" declaration statement that omits it. In case of the long declaration, the initialization is optional. A variable that is not explicitly initialized, is implicitly initialized with the [[Go_Language#Zero_Value|zero value]] for the variable's type. | |||
=<span id='Long'></span>Long Variable Declaration= | |||
The long declaration statement starts with the <code>[[Go_Language#var|var]]</code> keyword, followed by the name and the type of the variable: | |||
<syntaxhighlight lang='go'> | <syntaxhighlight lang='go'> | ||
var <variable-name>[, <variable-name-2>, ...] <type> | var <variable-name>[, <variable-name-2>, ...] <type> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Examples: | |||
<syntaxhighlight lang='go'> | <syntaxhighlight lang='go'> | ||
var size int | var size int | ||
Line 37: | Line 45: | ||
var size, weight int | var size, weight int | ||
</syntaxhighlight> | </syntaxhighlight> | ||
More variables of different types can be declared at the same time with: | |||
More variables can be declared at the same time with: | |||
<syntaxhighlight lang='go'> | <syntaxhighlight lang='go'> | ||
var ( | var ( | ||
a int | a, b int | ||
c string | |||
... | ... | ||
) | ) | ||
Line 52: | Line 58: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Also see: {{Internal|Variables,_Parameters,_Arguments#Variable|Variables, Parameters, Arguments}} | Also see: {{Internal|Variables,_Parameters,_Arguments#Variable|Variables, Parameters, Arguments}} | ||
==<span id='Declaration_without_Initialization'></span>Long Declaration without Initialization== | |||
= | A long declaration statement that is not followed by an explicit initialization implicitly initializes the variable with the [[Go_Language#Zero_Value|zero value]] of the variable's type. | ||
< | ==Variable Initialization in Long Declaration== | ||
Variables can be initialized in a long declaration as such: | |||
</ | |||
=Variable Initialization in Declaration= | |||
Variables can be initialized in | |||
<syntaxhighlight lang='go'> | <syntaxhighlight lang='go'> | ||
// Static analysis warning "Type can be omitted" | |||
var color string = "blue" | var color string = "blue" | ||
</syntaxhighlight> | </syntaxhighlight> | ||
However, the type declared as such is redundant, and some editors will render the type name in gray and pop up a soft static analysis warning: "Type can be omitted", because an alternative syntax, [[#Variable_Initialization_with_Type_Inference|initialization with type inference]] is available. | |||
==<span id='Variable_Initialization_with_Type_Inference'></span>Variable Initialization with Type Inference in Long Declaration== | |||
=Variable Initialization with Type Inference= | A long declaration and initialization statement can skip the explicit type declaration because the type can be inferred by the compiler, making its declaration retardant. The declaration is still "long" because the statement starts with the <code>var</code> keyword: | ||
<syntaxhighlight lang='go'> | <syntaxhighlight lang='go'> | ||
var color = "blue" | var color = "blue" | ||
</syntaxhighlight> | </syntaxhighlight> | ||
= | ==Variable Initialization after Long Declaration== | ||
The variable can be simply declared without initialization, and initialized as part of a subsequent statement: | |||
<syntaxhighlight lang='go'> | <syntaxhighlight lang='go'> | ||
var color string | |||
color = "blue" | |||
</syntaxhighlight> | </syntaxhighlight> | ||
=Short Variable Declaration= | =Short Variable Declaration= | ||
The declaration and initialization can be performed together with the <code>:=</code> operator. This obviates the need for the <code>[[#var|var]]</code> keyword and | The declaration and initialization can be performed together with the <code>:=</code> operator. This obviates the need for the <code>[[Go_Language#var|var]]</code> keyword and also the formal type declaration, which is replaced with [[#Variable_Initialization_with_Type_Inference_in_Long_Declaration|type inference]]. This kind of declaration can only be performed inside a [[Go Functions#Short_Variable_Declaration|function]]. | ||
<syntaxhighlight lang='go'> | <syntaxhighlight lang='go'> | ||
color := "blue" | color := "blue" | ||
Line 86: | Line 88: | ||
color, size := someFuncWithTwoReturnValues(...) | color, size := someFuncWithTwoReturnValues(...) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
==Short Variable Declaration, Redeclaration and Reassignment== | |||
The short variable declaration usually declares the variable, but it can also be used with variables that may have already been declared. There are three additional condition, though: | |||
# the short declaration is in the same scope as the existing variable (if the existing variable is declared in an outer scope, the short declaration will just create a new variable) | |||
# the corresponding value in the initialization is assignable to the existing variable | |||
# there must be '''at least one new variable''' that is created by the short declaration, in addition to the existing variables. | |||
It is said that the existing variables are '''re-assigned''', the existing variables are re-used and just given a new value: | |||
<syntaxhighlight lang='go'> | |||
var a = 1 // 'a' is declared | |||
a, b := someFunc() // 'a' is re-assigned, 'b' is declared | |||
... | |||
</syntaxhighlight> | |||
The short variable declaration fails if '''all''' variables have been previously declared: | |||
<syntaxhighlight lang='go'> | |||
var a = 1 // 'a' is declared | |||
var b = 2 // 'b' is declared | |||
a, b := someFunc() // Compilation fails with "No new variables on the left side of ':='" | |||
... | |||
</syntaxhighlight> | |||
This unusual variable reassignment rule is pure pragmatism, making it easy to use a single <code>err</code> variable in a long <code>if</code>/<code>else</code> chain. This syntax is often used. | |||
=Swap Variable Values= | |||
<syntaxhighlight lang='go'> | |||
a, b = b, a | |||
</syntaxhighlight> | |||
This syntax works with arrays and slices. | |||
=Variable Declaration with <tt>new()</tt>= | =Variable Declaration with <tt>new()</tt>= | ||
<code>new()</code> creates a variable or a certain type, specified as the argument of the <code>new()</code> function invocation, and returns a [[# | <code>new()</code> creates a variable or a certain type, specified as the argument of the <code>new()</code> function invocation, and returns a [[Pointers_in_Go#Overview|pointer]] to that variable. | ||
<syntaxhighlight lang='go'> | <syntaxhighlight lang='go'> | ||
ptri := new(int) | ptri := new(int) | ||
Line 94: | Line 129: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<font color=darkkhaki>Why do we need to involve variables here? There's no variable, new() just allocates space for an instance of a certain type and returns a pointer to it.</font> | <font color=darkkhaki>Why do we need to involve variables here? There's no variable, new() just allocates space for an instance of a certain type and returns a pointer to it.</font> | ||
=Creating instances with <tt>New()</tt>= | =Creating instances with <tt>New()</tt>= | ||
{{Internal|Go New()|Go <tt>New()</tt>}} | {{Internal|Go New()|Go <tt>New()</tt>}} | ||
=Scope= | =Scope= | ||
The scope of a variable is defined as places in the code where the variable can be accessed. In Go, the scope of a variable can be formally defined by using the concept of [[#Block|block]]: Go is a lexically scoped language using blocks. | The scope of a variable is defined as places in the code where the variable can be accessed. | ||
In Go, the scope of a variable can be formally defined by using the concept of [[#Block|block]]: Go is a lexically scoped language using blocks. | |||
Given two blocks b<sub>i</sub> and b<sub>j</sub>, we say that b<sub>i</sub> ≥ b<sub>j</sub> if b<sub>j</sub> is inside (is enclosed in) b<sub>i</sub>. This relationship is transitive. | Given two blocks b<sub>i</sub> and b<sub>j</sub>, we say that b<sub>i</sub> ≥ b<sub>j</sub> if b<sub>j</sub> is inside (is enclosed in) b<sub>i</sub>. This relationship is transitive. | ||
Line 106: | Line 144: | ||
If a variable with the same name is declared in two blocks between which there is a an inclusion relationship, the variable defined in the "closest" block takes precedence. | If a variable with the same name is declared in two blocks between which there is a an inclusion relationship, the variable defined in the "closest" block takes precedence. | ||
Also see: {{Internal|Go_Functions#Environment_of_a_Function|Environment of a Function}} | Also see: | ||
{{Internal|Go_Functions#Function_Parameters_and_Return_Value_Scope|Function Parameters and Return Value Scope}} | |||
{{Internal|Go_Functions#Environment_of_a_Function|Environment of a Function}} | |||
=Variable Deallocation= | =Variable Deallocation= | ||
{{Internal|Go_Language_Memory_Management_and_Garbage_Collection#Variable_Deallocation|Memory Management and Garbage Collection | Variable Deallocation}} | {{Internal|Go_Language_Memory_Management_and_Garbage_Collection#Variable_Deallocation|Memory Management and Garbage Collection | Variable Deallocation}} |
Latest revision as of 23:15, 12 September 2024
External
Internal
Overview
Variables are names associated with memory locations that store values. Variable name rules are described in the Naming section. The set of permissible values is determined by the variable's type. Each variable has a type. Because Go is a statically typed language, the type associate with a variable may not change after the declaration. Each variable defined in Go occupies a unique memory location. It is not possible to have two variables that share the same storage location. It is possible to have two variable that point to the same storage location, in case of pointer variables, but this is not the same thing as sharing the same storage location. In other words, Go has no reference variables. The value of a variable can change at runtime, unlike a const
's.
Naming
The names of variable identifiers in Go follow general naming conventions for identifiers.
Variable names should be short rather than long. The closer to declaration a name is used, the shorter it should be. Conversely, the farther away from the declaration you use it, the longer the name should be. Long variable names obscure what the code does. Longer names may help in long functions, or functions with many local variable, but often this just means you should refactor.
i
is fine when iterating over an array, prefer i
to index
. Prefer r
to reader
. Prefer b
to buffer
. Prefer count
to runeCount
inside a function named RuneCount
.
Two letter variable names should be used for slices or maps.
var tt []*Thing // tt is many
When choosing variable names, try to make them work well with their enclosing package name:
Go does not have reference variables, but it does have pointers, so one may assume that there are naming conventions to make obvious when a variable contains a pointer, and when it contains a value. In fact, there aren't such conventions. Pointer and value variable names are indistinguishable. For more details, see:
(No) Reference Variables
Go does not have reference variables. Each variable defined in Go occupies a unique memory location, which contains the value of the variable. Arrays, slices, maps, channels, etc. variables are all values, not references. As such, there is no pass-by-reference in Go, everything is passed by value. To achieve behavior similar to pass-by-reference, use pointers. This is explained here:
Variable Declaration and Initialization
In Go variables must be explicitly declared to be used. There is a "long" declaration statement that uses the var
keyword and a "short" declaration statement that omits it. In case of the long declaration, the initialization is optional. A variable that is not explicitly initialized, is implicitly initialized with the zero value for the variable's type.
Long Variable Declaration
The long declaration statement starts with the var
keyword, followed by the name and the type of the variable:
var <variable-name>[, <variable-name-2>, ...] <type>
Examples:
var size int
var size, weight int
More variables of different types can be declared at the same time with:
var (
a, b int
c string
...
)
A variable that can take any type can be declared using interface{}
or its equivalent any
:
var r any
Also see:
Long Declaration without Initialization
A long declaration statement that is not followed by an explicit initialization implicitly initializes the variable with the zero value of the variable's type.
Variable Initialization in Long Declaration
Variables can be initialized in a long declaration as such:
// Static analysis warning "Type can be omitted"
var color string = "blue"
However, the type declared as such is redundant, and some editors will render the type name in gray and pop up a soft static analysis warning: "Type can be omitted", because an alternative syntax, initialization with type inference is available.
Variable Initialization with Type Inference in Long Declaration
A long declaration and initialization statement can skip the explicit type declaration because the type can be inferred by the compiler, making its declaration retardant. The declaration is still "long" because the statement starts with the var
keyword:
var color = "blue"
Variable Initialization after Long Declaration
The variable can be simply declared without initialization, and initialized as part of a subsequent statement:
var color string
color = "blue"
Short Variable Declaration
The declaration and initialization can be performed together with the :=
operator. This obviates the need for the var
keyword and also the formal type declaration, which is replaced with type inference. This kind of declaration can only be performed inside a function.
color := "blue"
The short variable declaration can be used to initialize more than one variable at the same time, when the assignment contains multiple values, or when on the right side of the assignment there is a function that returns multiple values:
i, j := 0, 1
color, size := someFuncWithTwoReturnValues(...)
Short Variable Declaration, Redeclaration and Reassignment
The short variable declaration usually declares the variable, but it can also be used with variables that may have already been declared. There are three additional condition, though:
- the short declaration is in the same scope as the existing variable (if the existing variable is declared in an outer scope, the short declaration will just create a new variable)
- the corresponding value in the initialization is assignable to the existing variable
- there must be at least one new variable that is created by the short declaration, in addition to the existing variables.
It is said that the existing variables are re-assigned, the existing variables are re-used and just given a new value:
var a = 1 // 'a' is declared
a, b := someFunc() // 'a' is re-assigned, 'b' is declared
...
The short variable declaration fails if all variables have been previously declared:
var a = 1 // 'a' is declared
var b = 2 // 'b' is declared
a, b := someFunc() // Compilation fails with "No new variables on the left side of ':='"
...
This unusual variable reassignment rule is pure pragmatism, making it easy to use a single err
variable in a long if
/else
chain. This syntax is often used.
Swap Variable Values
a, b = b, a
This syntax works with arrays and slices.
Variable Declaration with new()
new()
creates a variable or a certain type, specified as the argument of the new()
function invocation, and returns a pointer to that variable.
ptri := new(int)
*ptri = 3
Why do we need to involve variables here? There's no variable, new() just allocates space for an instance of a certain type and returns a pointer to it.
Creating instances with New()
Scope
The scope of a variable is defined as places in the code where the variable can be accessed.
In Go, the scope of a variable can be formally defined by using the concept of block: Go is a lexically scoped language using blocks.
Given two blocks bi and bj, we say that bi ≥ bj if bj is inside (is enclosed in) bi. This relationship is transitive.
The formal definition of visibility (or accessibility) of a variable v
is: a variable v
is visible in a block bj if it is declared in a block bi so bi ≥ bj.
If a variable with the same name is declared in two blocks between which there is a an inclusion relationship, the variable defined in the "closest" block takes precedence.
Also see: