PASSWORD RESET

Your destination for complete Tech news

Go tutorial – Chapter 2: Go syntax and basic concepts

273 0
10 min read

Variables and types

Go is a statically-typed language, which means that variables have a fixed type that cannot be changed at runtime. Go has a number of built-in types, including:

  • bool: A boolean type representing true or false.
  • int, int8, int16, int32, int64: Integer types of different sizes.
  • uint, uint8, uint16, uint32, uint64: Unsigned integer types of different sizes.
  • float32, float64: Floating point types of different sizes.
  • complex64, complex128: Complex types of different sizes.
  • string: A string type representing a sequence of Unicode characters. You can declare a variable with a specific type using the var keyword:

In Go, variables are declared using the var keyword, followed by the variable name and the type. For example:

var x int
var y string

You can also declare and initialize variables in one line using the := operator:

x := 5
y := "hello"

Go has a number of built-in types, including integers, floating-point numbers, strings, and boolean values. You can also create your own types using structs. Example: Here is an example of declaring and using variables in Go:

package main

import "fmt"

func main() {
    // Declare and initialize variables using the `var` keyword
    var x int = 10
    var y string = "hello"
    var z bool = true

    // Declare and initialize variables using the `:=` operator
    a := 5
    b := "world"
    c := false

    fmt.Println(x, y, z)
    fmt.Println(a, b, c)
}

Output:

10 hello true
5 world false

In Go, variables can be of any type, including basic types, arrays, slices, maps, and structs. Go also has a number of type aliases, such as byte for uint8, rune for int32, and error for a type representing an error value.

Go has a number of type conversions, which allow you to convert a value from one type to another. For example, you can use the int function to convert a float64 to an int:

x := 3.14
y := int(x)

This converts the float64 value x to an int value y.

In addition to the built-in types, Go also allows you to define your own types using the type keyword. For example, you can define a type alias for an existing type:

type MyInt int

This defines a new type MyInt that is an alias for the int type. You can use MyInt like any other type:

var x MyInt = 10

You can also define a new type based on a struct or an interface. For example:

type Point struct {
    X int
    Y int
}

This defines a new type Point based on a struct with two fields X and Y, both of type int. You can create a value of this type using the struct keyword:

p := Point{1, 2}

You can access and modify the fields of a struct using the dot operator .:

p.X = 3
fmt.Println(p.Y)

You can also use the new function to create a pointer to a struct value:

q := new(Point)
q.X = 4
q.Y = 5

In this case, q is a pointer to a Point struct value. Example: Here is an example of defining a new type based on a struct:

package main

import "fmt"

type Point struct {
    X int
    Y int
}

func main() {
    p := Point{1, 2}
    q := new(Point)
    q.X = 4
    q.Y = 5

    fmt.Println(p)
    fmt.Println(q)
}

Output:

{1 2}
&{4 5}

Constants

Go has a built-in type called const for representing constant values. A constant is a value that cannot be changed at runtime. Constants can be of any type, including basic types, arrays, and structs. Constants are declared using the const keyword:

const Pi = 3.14

This declares a constant Pi of type float64 with the value 3.14. You can also specify the type of a constant explicitly:

const Pi float64 = 3.14

You can use the iota keyword to define a series of constants:

const (
    Monday = iota
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
    Sunday
)

This defines a series of constants Monday, Tuesday, Wednesday, etc., with the values 0, 1, 2, etc. iota is a predefined identifier that represents successive integer values in a constant declaration. The value of iota is reset to 0 whenever the const keyword is encountered. You can also use iota with expressions:

const (
    One = 1 << iota
    Two
    Four
    Eight
)

This defines a series of constants One, Two, Four, etc., with the values 1, 2, 4, etc. The << operator is the bit shift operator, which shifts the bits of a value to the left. Example: Here is an example of using constants in Go:

package main

import "fmt"

const Pi = 3.14

const (
    Monday = iota
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
    Sunday
)

const (
    One = 1 << iota
    Two
    Four
    Eight
)

func main() {
    fmt.Println(Pi)
    fmt.Println(Monday)
    fmt.Println(One)
    fmt.Println(Eight)
}

Output:

3.14
0
1
8

Constants are useful for defining values that are used throughout your code, such as mathematical constants, configuration parameters, and other values that should not change. They can also be used to define enums, which are a way to define a set of named constants.

In Go, constants are evaluated at compile-time, so they are not stored in memory at runtime. This means that you cannot take the address of a constant or use a constant as a pointer. Constants can also be used in place of named variables in expressions, but not in place of the keyword var or the := operator.

Functions

In Go, functions are declared using the func keyword, followed by the function name, a list of parameters, and the return type. For example:

func add(x int, y int) int {
    return x + y
}

You can also define functions with multiple return values:

func divmod(x int, y int) (int, int) {
    div := x / y
    mod := x % y
    return div, mod
}

To call a function, you can use its name and pass in the required arguments. For example:

result := add(5, 6)
div, mod := divmod(10, 3)

You can also define function arguments with default values by using the name=value syntax. For example:

func greet(name string, greeting string = "Hello") string {
    return greeting + " " + name
}

In this case, the greeting argument has a default value of “Hello”, so if it is not specified when the function is called, it will use the default value. Example: Here is an example of using functions in Go:

package main

import "fmt"

func add(x int, y int) int {
    return x + y
}

func divmod(x int, y int) (int, int) {
    div := x / y
    mod := x % y
    return div, mod
}

func greet(name string, greeting string = "Hello") string {
    return greeting + " " + name
}

func main() {
    fmt.Println(add(5, 6))
    fmt.Println(divmod(10, 3))
    fmt.Println(greet("John"))
    fmt.Println(greet("Jane", "Hi"))
}

Output

11
3 1
Hello John
Hi Jane

Control structures

Go has a number of control structures for controlling the flow of a program. These include:

if/else statements:

These are used to execute a block of code if a certain condition is true, and a different block of code if the condition is false. For example:

if x > y {
    fmt.Println("x is greater than y")
} else {
    fmt.Println("x is not greater than y")
}

You can also use else if clauses to test multiple conditions:

if x > y {
    fmt.Println("x is greater than y")
} else if x < y {
    fmt.Println("x is less than y")
} else {
    fmt.Println("x is equal to y")
}

for loops:

Go has two types of for loops: a traditional for loop and a range loop. The traditional for loop has the following syntax:

for i := 0; i < 10; i++ {
    fmt.Println(i)
}

The range loop is used to iterate over arrays, slices, maps, and strings. It has the following syntax:

numbers := []int{1, 2, 3, 4, 5}
for i, v := range numbers {
    fmt.Println(i, v)
}

This will print the index and value of each element in the numbers slice. You can also use the break and continue statements to control the flow of a loop. The break statement will exit the loop, while the continue statement will skip the rest of the current iteration and move on to the next one. Example: Here is an example of using for loops and control statements in Go:

package main

import "fmt"

func main() {
    // Traditional for loop
    for i := 0; i < 5; i++ {
        fmt.Println(i)
    }

    // Range loop
    numbers := []int{1, 2, 3, 4, 5}
    for i, v := range numbers {
        fmt.Println(i, v)
    }

    // Break statement
    for i := 0; i < 5; i++ {
        if i == 3 {
            break
        }
        fmt.Println(i)
    }

    // Continue statement
    for i := 0; i < 5; i++ {
        if i == 3 {
            continue
        }
        fmt.Println(i)
    }
}

Output:

0
1
2
3
4
0 1
1 2
2 3
3 4
4 5
0
1
2
0
1
2
4

switch statements:

Switch statements are used to execute a block of code based on the value of a variable. They have the following syntax:

switch x {
case 1:
    fmt.Println("x is 1")
case 2:
    fmt.Println("x is 2")
default:
    fmt.Println("x is not 1 or 2")
}

You can also use the fallthrough keyword to execute the code for the next case, regardless of whether the case condition is true. Example: Here is an example of using switch statements in Go:

package main

import "fmt"

func main() {
    x := 2

    switch x {
    case 1:
        fmt.Println("x is 1")
    case 2:
        fmt.Println("x is 2")
        fallthrough
    case 3:
        fmt.Println("x is 3")
    default:
        fmt.Println("x is not 1, 2, or 3")
    }
}

Output:

x is 2
x is 3

You can also use switch statements with conditions, using the syntax case x == y:. For example:

switch {
case x > y:
    fmt.Println("x is greater than y")
case x < y:
    fmt.Println("x is less than y")
default:
    fmt.Println("x is equal to y")
}

In this case, the switch statement will evaluate each case condition and execute the corresponding block of code if the condition is true.

Pointers

Pointers are a way to store the memory address of a value. In Go, pointers are represented using the * operator. You can declare a pointer to a value using the * operator:

var x int = 10
var p *int = &x

This declares a variable p of type *int, which is a pointer to an int value. The & operator is the address-of operator, which returns the memory address of a value. You can dereference a pointer using the * operator:

fmt.Println(*p)

This prints the value of x through the pointer p. You can also use the * operator to modify the value of a pointer:

*p = 20
fmt.Println(x)

This modifies the value of x through the pointer p. You can use the new function to create a pointer to a value:

q := new(int)
*q = 30
fmt.Println(*q)

This creates a new int value and stores it in q, which is a pointer to the value. Example: Here is an example of using pointers in Go:

package main

import "fmt"

func main() {
    var x int = 10
    var p *int = &x
    *p = 20
    fmt.Println(x)

    q := new(int)
    *q = 30
    fmt.Println(*q)
}

Output:

20
30

Pointers are a powerful feature of Go that allow you to manipulate values indirectly, through their memory addresses. They can be used to pass values by reference, to avoid copying large values, and to implement complex data structures such as linked lists and trees. However, they can also be confusing and error-prone, especially for new Go programmers. It is important to use pointers carefully and understand their behavior.

In Go, pointers are always of a fixed size, regardless of the type of the value they point to. This means that you can store a pointer to any value in a variable of type *int, for example. However, you cannot use a pointer to a value of a different type. For example, you cannot use a *string pointer to modify an int value. Pointers are also not compatible with the arithmetic and comparison operators, with the exception of the == and != operators, which can be used to compare the values of two pointers.

Go has a built-in type called struct for defining composite data types. A struct is a collection of fields, each with a name and a type. For example:

type Point struct {
    X int
    Y int
}

This defines a new struct type Point with two fields X and Y, both of type int. You can create a new struct value using the struct keyword and the field values:

p := Point{1, 2}

You can access and modify the fields of a struct using the dot operator .:

p.X = 3
fmt.Println(p.Y)

You can also use the new function to create a pointer to a struct value:

q := new(Point)
q.X = 4
q.Y = 5

In this case, q is a pointer to a Point struct value. You can define methods on structs by specifying a receiver type. A method is a function with a special receiver argument that is bound to the struct. For example:

func (p *Point) Distance() float64 {
    return math.Sqrt(float64(p.X*p.X + p.Y*p.Y))
}

This defines a method Distance on the Point struct type with a receiver type of *Point. The method returns the distance of the point from the origin using the Pythagorean theorem. You can call a method on a struct value or a pointer to a struct value using the dot operator:

fmt.Println(p.Distance())
fmt.Println(q.Distance())

This will print the distance of the points p and q from the origin. Example: Here is a complete example of using structs and methods in Go:

package main

import (
    "fmt"
    "math"
)

type Point struct {
    X int
    Y int
}

func (p *Point) Distance() float64 {
    return math.Sqrt(float64(p.X*p.X + p.Y*p.Y))
}

func main() {
    p := Point{1, 2}
    q := new(Point)
    q.X = 4
    q.Y = 5

    fmt.Println(p.Distance())
    fmt.Println(q.Distance())
}
Output:
2.23606797749979
6.4031242374328485

Error Handling

In Go, errors are represented using the error type, which is a built-in interface with a single method:

type error interface {
    Error() string
}

The Error method returns a string description of the error. You can use the error type to represent any error that may occur in your program. For example:

if err != nil {
    return err
}

This returns the err value as an error if it is not nil. You can create a new error value using the errors.New function:

err := errors.New("invalid input")

This creates a new error value with the message “invalid input”. You can also use the fmt.Errorf function to create a formatted error message:

err := fmt.Errorf("invalid input: %v", input)

This creates a new error value with the message “invalid input: input”, where input is the value of the input variable. You can check if an error value is nil to determine if an error has occurred:

if err != nil {
    fmt.Println(err)
}

This prints the error message if err is not nil. You can use the defer keyword to ensure that a function is always executed, even if an error occurs:

func foo() error {
    file, err := os.Open("file.txt")
    if err != nil {
        return err
    }
    defer file.Close()
    // do something with file
    return nil
}

This opens the “file.txt” file and ensures that it is always closed, even if an error occurs while opening the file.

Error handling is an important part of programming in Go. It allows you to handle and recover from errors that may occur during the execution of your program. You can use the error type and the errors and fmt packages to create and manipulate error values, and the defer keyword to ensure that necessary actions are always taken.

Packages and Importing

In Go, a package is a collection of related Go source files that are compiled and installed together. A package usually consists of one or more Go source files located in the same directory and sharing the same package name.

To use a package in your Go program, you need to import it first. You can import a package using the import keyword:

import "fmt"

This imports the fmt package, which provides formatting and I/O functions. You can import multiple packages at once:

import "fmt"
import "math"

You can also use the import keyword with the . notation to import all the identifiers in a package into the current namespace:

import . "fmt"

This imports all the identifiers in the fmt package into the current namespace, so you don’t have to use the fmt. prefix to access them. You can also use the import keyword with the _ notation to import a package for its side effects only, without accessing its identifiers:

import _ "database/sql"

This imports the database/sql package, which initializes some global variables, but does not bring any of its identifiers into the current namespace. You can also use the import keyword with the as notation to give an imported package a different name in your program:

import f "fmt"

This imports the fmt package as f, so you have to use the f. prefix to access its identifiers.

Packages and importing are important concepts in Go. Packages allow you to organize your Go source code and share it with others, and importing allows you to use the code in other packages in your program. You can use the import keyword to import packages and access their identifiers, and the . and _ notations to import packages for their side effects only or to give them different names.

Leave A Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.