Keywords and Operators in Go
Before we jump into types, let's take a quick look at the keywords and operators in Go. Understanding these will help you grasp the language's syntax and functionality.
Keywords
Go has a surprisingly small set of keywords, which keeps the language simple and easy to understand. Here’s a list of Go keywords:
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
Operators
Go operators can be categorized into arithmetic, comparison, logical, bitwise, and others:
Arithmetic Operators
+ // Addition
- // Subtraction
* // Multiplication
/ // Division
% // Remainder
Comparison Operators
== // Equal
!= // Not equal
< // Less than
<= // Less than or equal to
> // Greater than
>= // Greater than or equal to
Logical Operators
&& // Logical AND
|| // Logical OR
! // Logical NOT
Bitwise Operators
& // AND
| // OR
^ // XOR
<< // Left shift
>> // Right shift
Other Operators
& // Address of
* // Pointer dereference
<- // Send/receive operator for channels
Special Operators
Assignment Operators
= // Assignment
+= // Addition assignment
-= // Subtraction assignment
*= // Multiplication assignment
/= // Division assignment
%= // Remainder assignment
&= // AND assignment
|= // OR assignment
^= // XOR assignment
<<= // Left shift assignment
>>= // Right shift assignment
Increment and Decrement Operators
++ // Increment
-- // Decrement
Now that we have an overview of the keywords and operators, let's move on to understanding how Go handles different types of data.
Numbers in Go vs. Interpreted Languages
One of the first things to understand about Go is how it handles numbers, especially compared to interpreted languages like Python.
Interpreted Languages
In languages like Python:
x = 10
Here, x
is an object that represents the number 10. The interpreter takes care of converting this into something the computer understands. Essentially, x
is not directly a number but an object that the interpreter manages.
Go
In Go:
var y int = 10
y
is directly a memory location containing the value 10. This direct approach gives Go a performance edge because there's no intermediary interpreter. This difference is fundamental to Go’s type system and performance.
Basic Integer Types
In Go, the default integer type is int
. There are also various sized integers, both signed and unsigned, but for most purposes, you’ll use int
.
Integer Types
Go provides several integer types:
int: Platform-dependent (32-bit or 64-bit)
int8: 8-bit signed integer
int16: 16-bit signed integer
int32: 32-bit signed integer
int64: 64-bit signed integer
uint: Platform-dependent unsigned integer
uint8: 8-bit unsigned integer (alias for byte)
uint16: 16-bit unsigned integer
uint32: 32-bit unsigned integer
uint64: 64-bit unsigned integer
Example
var y int = 10 // Declare an int variable
y := 10 // Short declaration, also creates an int
Float Types
For real numbers (fractions), Go has float32
and float64
, with float64
being the default.
var f float64 = 7.89 // Declare a float64 variable
f := 7.89 // Short declaration, also creates a float64
Type Inference
Go can infer the type of a variable based on its initial value.
var b = 7.89 // Inferred as float64
var i = 10 // Inferred as int
Type Conversion
Go is strict about type conversion. You can’t just mix types without explicitly converting them.
var y int = 15
var b float64 = 15.5
y = int(b) // Convert float64 to int, fractional part is discarded
b = float64(y) // Convert int to float64
Code Example: Playing with Types
Here's a simple program to illustrate the basics of type declarations and conversions.
package main
import (
"fmt"
)
func main() {
var y int = 10
b := 15.5
fmt.Printf("y: %T, %v\n", y, y)
fmt.Printf("b: %T, %v\n", b, b)
y = int(b)
fmt.Printf("y after conversion: %T, %v\n", y, y)
}
Run this in the Go Playground and you'll see how types and conversions work.
Booleans and Errors
Boolean Type
Booleans in Go are straightforward—either true
or false
.
var isAvailable bool = true
isCompleted := false
Error Type
Errors are a bit more complex but for now, think of them as either nil
or containing an error message.
var err error = nil
if err != nil {
fmt.Println("An error occurred")
}
Declarations and Initialization
Go ensures all variables are initialized at declaration, either by you or by default to zero values.
var x int // x is initialized to 0
y := 0 // y is explicitly initialized to 0
Example of Default Initialization
Here's a more detailed example showing default initialization:
package main
import (
"fmt"
)
func main() {
var i int
var f float64
var b bool
var s string
fmt.Printf("%v %v %v %q\n", i, f, b, s)
// Output: 0 0 false ""
}
Constants
Constants in Go are immutable. They can only be numbers, booleans, or strings.
Declaring Constants
const pi = 3.14159
const greeting = "Hello, World!"
Using Constants
Constants are evaluated at compile time and can be used in expressions:
const (
a = 5
b = 10
c = a + b // c = 15
)
Practical Example: Calculating Averages
Let's build a simple program to calculate averages from a list of numbers, either from the command line or a file.
package main
import (
"bufio"
"fmt"
"os"
"strconv"
)
func main() {
var sum float64
var count int
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
val, err := strconv.ParseFloat(scanner.Text(), 64)
if err != nil {
fmt.Fprintln(os.Stderr, "Invalid input:", err)
return
}
sum += val
count++
}
if count == 0 {
fmt.Println("No values provided")
return
}
fmt.Printf("Average: %.2f\n", sum/float64(count))
}
How It Works
Reading Input: We read input line by line using a scanner.
Converting Input: Each line is converted to a
float64
usingstrconv.ParseFloat
.Summing Values: The values are summed, and the count of inputs is maintained.
Calculating Average: The average is calculated by dividing the sum by the count.
You can test this by running the program and providing numbers either directly or through a file.
Example Usage
From the Command Line
$ go run main.go
8
9
10
Ctrl+D
From a File
$ cat numbers.txt
8
9
10
$ go run main.go < numbers.txt
Understanding Strings in Go
Declaring Strings
Strings in Go are sequences of bytes. Go strings are immutable, meaning once created, they cannot be changed.
var message string = "Hello, World!"
message := "Hello, World!"
String Operations
You can concatenate strings using the +
operator:
part1 := "Hello, "
part2 := "World!"
message := part1 + part2 // message = "Hello, World!"
String Functions
Go provides a variety of functions for working with strings in the strings
package:
import (
"fmt"
"strings"
)
func main() {
message := "Hello, World!"
fmt.Println(strings.ToUpper(message)) // "HELLO, WORLD!"
fmt.Println(strings.Contains(message, "World")) // true
}
Composite Types: Slices and Maps
Slices
Slices are a key data type in Go, providing a more powerful interface for sequences than arrays.
var numbers []int // Declare a slice
numbers = append(numbers, 3, 6, 9) // Append values to the slice
Maps
Maps are Go's built-in associative data type (hash table or dictionary).
var ages map[string]int // Declare a map
ages = make(map[string]int) // Initialize the map
ages["Alice"] = 25 // Assign a value
fmt.Println(ages["Alice"]) // Retrieve a value
Example: Using Slices and Maps
Here's a more detailed example demonstrating slices and maps:
package main
import (
"fmt"
)
func main() {
// Slices
numbers := []int{3, 6, 9, 12, 15}
fmt.Println(numbers)
numbers = append(numbers, 18)
fmt.Println(numbers)
// Maps
ages := make(map[string]int)
ages["Charlie"] = 22
ages["Dana"] = 28
fmt.Println(ages)
fmt.Println("Charlie’s age:", ages["Charlie"])
}
We've covered the basics of types in Go, including integers, floats, booleans, errors, strings, and composite types like slices and maps. We also touched on variable declarations, type inference, and conversions. By building a simple average calculator and exploring string and composite type operations, we've put these concepts into practice. Next, we'll dive into more advanced topics like functions, methods, and concurrency. Happy coding!