What is a variable? Why do we need them?
What is a type?
How to create a variable?
How to assign a value to a variable?
How to use variables?
What is a constant? What are the differences between a constant and a variable?
How to define a constant?
How to use constants?
Variable
Constant
Type
Untyped constants
A variable is a space in the computer memory that can contain a changeable piece of data. The term “variable” comes from the Latin word “variabilis” which means “changeable”. In programs, we can create variables that will allow you to store information for later use.
\nFor instance, we want to keep track of the number of guests in a hotel. The number of guests is a number that will vary. We can create a variable to store this information (see 1).
\nWe talked previously about ROM, RAM, and auxiliary memory. Where is a Go variable stored? The answer is short; you cannot choose where it will be held. This is the responsibility of the compiler, not yours!
\n\nIn most programming language (and also in Go), when we create a variable we associate it to an identifier. The identifier is the “name” of the variable. Giving identifiers to variables allow us to use them quickly in our program. An identifier is composed of letters and digits. The identifier of the variable will be used inside the program to designate the value that is stored inside. The identifier must be short and descriptive.
\nTo create identifiers, programmers can be creative. But they must follow those simple rules :
\nIdentifiers are composed of
\nThe identifier must start with a letter or with the underscore character.“_”
Some identifiers cannot be used because they are reserved by the language
\nnumberOfGuests
\nis a valid identifier for a variable.
\n113Guests
\nis not valid because it starts with a digit.
\n\nWe can store information into a variable. The term information is vague; we have to be more precise. Do we need to store digits (1, 2000, 3), floating-point numbers (2.45665), a text (“Room 112 non-smoking”)? A variable has a set of permissible values that we can assign to it. This set is the type of the variable. Types have names.
\nThe Go language predeclares a set of basic types that you can use right away into your programs. You can also define your types (we will see it later). For the moment, we will focus only on the most used types :
\nCharacter strings :
\nType Name: string
Ex : “management office”, “room 265”,...
Unsigned integers
\nType names: uint, uint8, uint16, uint32, uint64
Ex : 2445, 676, 0, 1,...
Integers
\nType Names: int, int8, int16, int32, int64
Ex : -1245, 65, 78,...
Booleans
\nType Name: bool
Ex : true, false
Floating point numbers
\nType Name: float32, float64
Ex : 12.67
You may have noticed that we have five flavors of integers: int, int8, int16, int32, int64. The same is happening for unsigned integers. We have uint, uint8, uint16, uint32 and uint64. The choice is more limited for the floating-point numbers: we can use float32 or float64.
\nIf you want to store a number that does not have a sign, you can use unsigned integers types. Those types come in 5 flavors:
\nuint8
unit16
uint32
uint64
uint
Except for the last one, each one has a number appended to it. The number corresponds to the number of bits of memory allocated to store it.
\nIf you have read the first section, you know that :
\nwith 8 bits of memory, we can store the decimal numbers from 0 to 2^{7}+2^{6}+...+2^{0}=255.
with 16 bits (2 bytes) we can store numbers from 0 to 2^{15}+2^{14}+...+2^{0}=65.535
with 32 bits (4 bytes) we can store numbers from 0 to 2^{31}+2^{30}+...+2^{0}=4.294.967.295
with 64 bits (8 bytes) we can store numbers from 0 to 2^{63}+2^{62}+...+2^{0}=18.446.744.073.709.551.615
You can note that the maximum decimal value of 64 bits is very high. Keep that in mind! If you need to store a value that does not exceed 255 use uint8 instead of uint64. Otherwise, you will waste storage (because you will only use 8 bits of the 64 bits allocated in memory !)
\nThe last type is uint. If you use this type in your program, the memory allocated for your unsigned integer will be at least 32 bits. It will depend on the system that will run the program. If it’s a 32-bit system, it will be equivalent to uint32. If the system is 64 bits, then the storage capacity of uint it will be identical to the one of uint64. (to better understand the difference between 32 bits and 64 bits, you can take a look at the previous chapter)
\n\nIf you want to use a variable in your program, you need to declare it before.
\n\nWhen you declare a variable, it will :
\nBind an identifier to the variable
Bind a type to the variable
Initialize the variable value to the default value of the type
If you are used to programming the first two develop the first two actions are common. But the third one is not. Go initialize the value for you to the default of its type. Uninitialized variables do not exist in Go.
\n\nIn the figure 2 you can see how to declare variables. In the first example, we declare one variable of type int named roomNumber. In the second one, we declare two variables in the same line : roomNumber and floorNumber. They are of type int. Their value will be 0 (which is the zero value of the type int).
\n// variables-constants-and-basic-types/declaration-without-initializer/main.go\npackage main\n\nimport "fmt"\n\nfunc main() {\n var roomNumber, floorNumber int\n fmt.Println(roomNumber, floorNumber)\n\n var password string\n fmt.Println(password)\n}
\nThis program outputs :
\n0 0
\nThe variable password of type string is initialized with the zero value of the type string, which is an empty string \"\". The variables roomNumber and floorNumber are initialized to the zero value of type int, which is 0.
\nThe first line of the program output is the result of fmt.Println(password)
. The second line is the result of fmt.Println(roomNumber,floorNumber)
.
You can also declare a variable and initialize its value directly. The possible syntax is described in the figure 3. Let’s take an example :
\n// variables-constants-and-basic-types/declaration-variant/main.go\npackage main\n\nimport "fmt"\n\nfunc main() {\n var roomNumber, floorNumber int = 154, 3\n fmt.Println(roomNumber, floorNumber)\n\n var password = "notSecured"\n fmt.Println(password)\n}
\nIn the main
function, the first statement declares two variables roomNumber and floorNumber. They are of type int
and initialized with the values 154 and 3. Then the program will print those variables.
There is an expression or a list of expressions at the equal sign’s left. We will cover expressions in detail in another section.
\nThen we define the variable password
. We initialize it with the value \"notSecured\"
. Note here that the type is not written. Go will give the variable the type of the initialization value. Here the type of \"notSecured\"
is a string; thus, the type of the variable password
is a string.
The short syntax eliminates the var keyword. The =
sign is transformed into :=
.You can also use this syntax to define multiple variables at once.
roomNumber := 154
\nThe type is not written explicitly. The compiler will infer it from the expression (or the expression list).
\nHere is an example :
\n// variables-constants-and-basic-types/short-declaration/main.go\npackage main\n\nimport "fmt"\n\nfunc main() {\n roomNumber, floorNumber := 154, 3\n fmt.Println(roomNumber, floorNumber)\n}
\n// will not compile\npackage main\n\nvatRat := 20\n\nfunc main(){\n\n}
\nnil
for a short variable declaration. The compiler cannot infer the type of your variable.Constant comes from the Latin word “constare” which means\"standing firm\". A constant is a value in your program that will stand firm, that will not change during the execution. A variable can change during the runtime; a constant will not change; it will stay constant.
\nFor instance, we can store in a constant :
\nThe version of our program. For instance : “1.3.2”. This value will stay stable during program runtime. We will change this value when we compile another version of our program.
The build time of the program.
An email template (if not configurable by our application).
An error message.
In summary, use a constant when you are sure that you will never need to change a value during program execution. We say that a constant is immutable. Constants come in two flavors: typed and untyped.
\n\nHere is a typed constant :
\nconst version string = "1.3.2"
\nThe keyword const signal to the compiler that we will define a constant. After the const keyword, the identifier of the constant is set. In our example, the identifier is “version”. The type is explicitly defined (here string) and also the value of the constant (in the form of an expression).
\nHere is an untyped constant :
\nconst version = "1.3.2"
\nAn untyped constant :
\nhas no type
has a default type
has no limits
Let’s take an example to demonstrate the first point (an untyped constant has no type)
\n// variables-constants-and-basic-types/untyped-const/main.go\npackage main\n\nimport "fmt"\n\nfunc main() {\n const occupancyLimit = 12\n\n var occupancyLimit1 uint8\n var occupancyLimit2 int64\n var occupancyLimit3 float32\n\n // assign our untyped const to an uint8 variable\n occupancyLimit1 = occupancyLimit\n // assign our untyped const to an int64 variable\n occupancyLimit2 = occupancyLimit\n // assign our untyped const to an float32 variable\n occupancyLimit3 = occupancyLimit\n\n fmt.Println(occupancyLimit1, occupancyLimit2, occupancyLimit3)\n}
\nIn this program, we begin by defining an untyped constant. Its name is occupancyLimit
and its value is 12. At this point in the program, the constant has no particular type. Except it has been set to an integer value.
Then we define 3 variables : occupancyLimit1
, occupancyLimit2
, occupancyLimit2
(types of those variables are uint8, int64, float32).
Then we assign to those variables the value of occupancyLimit
. Our program compiles. The value of our constant can be put into variables of different types!
To understand the notion of default type, let’s take another example
\n// variables-constants-and-basic-types/default-type/main.go\npackage main\n\nimport "fmt"\n\nfunc main() {\n const occupancyLimit = 12\n\n var occupancyLimit4 string\n\n occupancyLimit4 = occupancyLimit\n\n fmt.Println(occupancyLimit4)\n}
\nIn this program, we define a constant occupancyLimit
which has a value of 12 (an integer). We define a variable occupancyLimit4
with a string type. Then we try to assign to occupancyLimit4
the value of our constant.
We try to convert an integer to a string. Will this program compile? The answer is no! The compilation error is :
\n ./main.go:10:19: cannot use occupancyLimit (type int) as type string in assignment
\nAn untyped constant has a default type that is defined by the value assigned to it at compilation. In our example, occupancyLimit
has a default type of int
. An int
cannot be assigned to a string
variable.
Untyped constants default types are :
\nbool (for any boolean value)
rune (for any rune value)
int (for any integer value)
float64 (for any floating-point value)
complex128 (for any complex value)
string (for any string value)
// variables-constants-and-basic-types/untyped-default/main.go\npackage main\n\nfunc main() {\n\n // default type is bool\n const isOpen = true\n // default type is rune (alias for int32)\n const MyRune = 'r'\n // default type is int\n const occupancyLimit = 12\n // default type is float64\n const vatRate = 29.87\n // default type is complex128\n const complexNumber = 1 + 2i\n // default type is string\n const hotelName = "Gopher Hotel"\n\n}
\n\nAn untyped constant has no type and a default type when needed. The value of an untyped constant can overflow its default type. Such a constant has no type; consequently, it does not depend on any type restriction. Let’s take an example :
\n// variables-constants-and-basic-types/untyped-no-limit/main.go\npackage main\n\nfunc main() {\n // maximum value of an int is 9223372036854775807\n // 9223372036854775808 (max + 1 ) overflows int\n const profit = 9223372036854775808\n // the program compiles\n}
\nIn this program, we create an untyped constant named profit. It’s value is 9223372036854775808 which overflows the maximum value allowed for an int (int64
on my 64-bits machine) : 9223372036854775807. This program compiles perfectly. But when we try to assign this constant value to a typed variable, the program will not compile. Let’s take an example to demonstrate it :
// variables-constants-and-basic-types/untyped-no-limit-2/main.go\npackage main\n\nimport "fmt"\n\nfunc main() {\n // maximum value of an int is 9223372036854775807\n // 9223372036854775808 (max + 1 ) overflows int\n const profit = 9223372036854775808\n var profit2 int64 = profit\n fmt.Println(profit2)\n}
\nThis program defines a variable profit2
which is of type int64
. We then try to assign to profit2
the value of the untyped constant profit
.
Let’s try to compile the program :
\n$ go build main.go\n# command-line-arguments\n./main.go:9:7: constant 9223372036854775808 overflows int64
\nWe get a compilation error, and that’s fine. What we are trying to do is illegal.
\n\nYou improve the readability of your programs
\nCompare this :
\nloc, err := time.LoadLocation(UKTimezoneName)\nif err != nil {\n return nil, err\n}
\nTo this :
\nloc, err := time.LoadLocation("Europe/London")\nif err != nil {\n return nil, err\n}
\nWe use the constant UKTimezoneName
instead of the raw value \"Europe/London\"
. We hide the complexity of the timezone string to the reader. In addition to that, the reader will understand what our intention was; we want to load the UK’s location.
You allow potential reuse of the value (by another program or in your own program)
The compiler might improve the machine code produced. You say to the compiler that this value will never change; if the compiler is smart (and it is), it will ingeniously use it.
Naming variables and constants is not an easy task. When you choose a name, you have to be sure that the selected name gives the right amount of information about its designation. The other developers that work on the same project will be thankful if you choose a good identifier name because reading the code will be easier. When we say “convey the right amount of information” the word “right” is vague. There are no scientific rules for naming program constructs. Even though there are no scientific rules, I can give you some advice shared among our community.
\nAvoid names with one letter: it conveys too little information about what is stored.
\nk
, i
and j
(inside loops, that we will cover later)Use camel case: this is a well-established convention in the go community.
\nNo more than two words
\nprofitValue
is good, profitValueBeforeTaxMinusOperationalCosts
is too longAvoid mentioning the type in the name
\ndescriptionString
is bad, description
is better
Go is already statically typed; you do not need to give the type information to the reader. (In some loosely typed language, it’s sometimes necessary to avoid confusion)
Write a program that will :
\nCreate a string constant named hotelName
and with value \"Gopher Hotel\"
Create two untyped constants that will contain respectively 24.806078 and -78.243027. The names of those two constants are longitude
and latitude
. (somewhere in the Bahamas)
Create a variable of type int
named occupancy
which is initialized with the value 12.
Print the hotelName
the longitude
, the latitude
and the occupancy
on a new line
What is the default type of longitude
and latitude
?
What is the type of longitude
?
The variable occupancy
is of type int
. Is it a 64, 32, or 8-bits integer ?
// variables-constants-and-basic-types/mission-solution/main.go\npackage main\n\nimport "fmt"\n\nfunc main() {\n const hotelName string = "Gopher Hotel"\n const longitude = 24.806078\n const latitude = -78.243027\n var occupancy int = 12\n fmt.Println(hotelName, longitude, latitude)\n fmt.Println(occupancy)\n}
\nWe begin with the definition of the typed constant hotelName
and the definition of longitude
and latitude
(which are untyped). Then we define the variable occupancy
(type: int
) and set its value to 12. Note that another syntax is possible :
occupancy := 12
\n var occupancy = 12
\nvar occupancy int \noccupancy = 12
\n\nWhat is the default type of longitude
and latitude
?
What is the type of longitude
?
latitude
.The variable occupancy
is of type int
. Is it a 64, 32, or 8-bits integer ?
int
is a type that has an implementation-specific size on a 32-bits computer it will be a 32 bits integer (int32); on a 64-bits computer, it will be a 64 bits integer (int64)What is an identifier?
By which type of character should an identifier begin?
What is the type of a variable?
What is a byte?
When you declare a type bool variable, what is its value (right after initialization)?
What are the two main characteristics of an untyped constant?
What is an identifier?
\nBy which type of character should an identifier begin?
\nWhat is the type of a variable?
\nWhat is a byte?
\nWhen you declare a variable of type bool. What is its value (right after initialization)?
\nWhat are the three characteristics of an untyped constant?
\nIt has no type
It has a default type
It has no limit
The name of a variable or constant is called an identifier
Identifiers are generally written using camelCase
Variables and constants allow you to save a value in memory
Constants are immutable, meaning that we cannot change their value during program execution
Variables have a type, which defines the set of values they can hold
When you create a variable, its value is initialized with the zero value of its type
\nThis one is super important...
It can be a source of mistakes.
There are NO uinitialized variables in Go.
There are two flavors of constants
\nTyped
Untyped
\nPrevious
\n\t\t\t\t\t\t\t\t\tHexadecimal, octal, ASCII, UTF8, Unicode, Runes
\n\t\t\t\t\t\t\t\tNext
\n\t\t\t\t\t\t\t\t\tControl Statements
\n\t\t\t\t\t\t\t\t