DEV Community

Cover image for Mastering Go: A Comprehensive Guide to Golang Syntax | Part - 1
Sahil Sojitra
Sahil Sojitra

Posted on • Updated on

Mastering Go: A Comprehensive Guide to Golang Syntax | Part - 1

Welcome to "Mastering Go: A Comprehensive Guide to Golang Syntax." In this blog, we will dive deep into the syntax of the Go programming language. Whether you are a beginner getting started with Go or an experienced developer looking to enhance your Go skills, this guide will provide you with a solid foundation in Go syntax.

To get started, you'll need to set up your Go development environment. Follow the steps below to ensure you have everything you need to follow along with the guide:

  1. Download and Install Go:

    • Visit the official Go website at golang.org.
    • Go to the downloads section and select the appropriate installer for your operating system.
    • Run the installer and follow the installation instructions.
  2. Configure Environment Variables:

    • After installing Go, you need to set up the necessary environment variables.
    • On Windows, open the Control Panel and navigate to System > Advanced System Settings > Environment Variables. Add the Go binary path (e.g., C:\Go\bin) to the PATH variable.
    • On macOS or Linux, open your terminal and edit your shell configuration file (e.g., ~/.bashrc or ~/.bash_profile) to include the Go binary path (e.g., export PATH=$PATH:/usr/local/go/bin).
  3. Verify the Installation:

    • Open a new terminal or command prompt window.
    • Run the following command to check if Go is installed and configured correctly:
 go version
Enter fullscreen mode Exit fullscreen mode
  • You should see the installed Go version printed in the terminal.

Now that your Go development environment is set up, you're ready to embark on your journey to mastering Go syntax.

Let's start with the classic "Hello, World!" program in Go. Follow these steps:

  • Open a text editor or an integrated development environment (IDE) of your choice.
  • Create a new file with a '.go' extension, such as 'hello.go'.
  • In the file, enter the following code:
package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}
Enter fullscreen mode Exit fullscreen mode
  • Save the file.
  • Open a terminal or command prompt and navigate to the directory where you saved the 'hello.go' file.
  • Compile the Go code by running the following command:
go build hello.go
Enter fullscreen mode Exit fullscreen mode
  • After the compilation is successful, an executable file named hello (or hello.exe on Windows) will be generated in the same directory.
  • Run the executable by executing the following command:
./hello  # On Unix-like systems (Linux, macOS)
hello    # On Windows
Enter fullscreen mode Exit fullscreen mode
  • You should see the output 'Hello, World!' displayed in the terminal.

Packages

  • Every Go program is made up of packages.
  • Programs start running in package main.
  • This program is using the packages with import paths "fmt" and "math/rand".
  • By convention, the package name is the same as the last element of the import path. For instance, the "math/rand" package comprises files that begin with the statement package rand.
package main

import (
    "fmt"
    "math/rand"
)

func main() {
    fmt.Println("My favorite number is", rand.Intn(177))
    /* Will Print Random Number in the Range of 0 to 177 */
}
Enter fullscreen mode Exit fullscreen mode

Output:

My favorite number is 90
Enter fullscreen mode Exit fullscreen mode

Imports

  • This code groups the imports into a parenthesized, "factored" import statement.
  • You can also write multiple import statements, like:

import "fmt"
import "math"

  • But it is good style to use the factored import statement.
package main

import (
    "fmt"
    "math"
)

func main() {
    fmt.Printf("Now you have %g problems.\n", math.Sqrt(16))
}

Enter fullscreen mode Exit fullscreen mode

Output:

Now you have 4 problems.
Enter fullscreen mode Exit fullscreen mode

Exported Names

  • In Go, a name is exported if it begins with a capital letter. For example, Pizza is an exported name, as is Pi, which is exported from the math package.
  • pizza and pi do not start with a capital letter, so they are not exported.
  • When importing a package, you can refer only to its exported names. Any "unexported" names are not accessible from outside the package.
package main

import (
    "fmt"
    "math"
)

func main() {
    fmt.Println(math.pi) /* Error */
    fmt.Println(math.Pi) /* 3.141592653589793 */
}
Enter fullscreen mode Exit fullscreen mode

Functions

  • A function can take zero or more arguments.
  • In this example, add takes two parameters of type int. Notice that the type comes after the variable name.
  • When two or more consecutive named function parameters share a type, you can omit the type from all but the last.
package main

import "fmt"

/* we shortened */
func add_(x, y int) int {
    return x + y
}

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

func main() {
    fmt.Println(add(100,50))
    fmt.Println(add_(200,50))
}
Enter fullscreen mode Exit fullscreen mode

Output:

150
250
Enter fullscreen mode Exit fullscreen mode
  • A function can return any number of results.
  • The swap function returns two strings.
  • A return statement without arguments returns the named return values. This is known as a "naked" return.
  • Naked return statements should be used only in short functions, as with the example shown here. They can harm readability in longer functions.
package main

import "fmt"

func swap(x, y string) (string, string) {
    return y, x
}

func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
/* Naked Return */
    return
}

func main() {
    a, b := swap("Hello", "World")
    fmt.Println(a, b)
    fmt.Println(split(17))
}
Enter fullscreen mode Exit fullscreen mode

Output:

World Hello
7 10
Enter fullscreen mode Exit fullscreen mode

Variables

  • The var statement declares a list of variables; as in function argument lists, the type is last.
  • A var declaration can include initializers, one per variable.If an initializer is present, the type can be omitted; the variable will take the type of the initializer.
  • the := short assignment statement can be used in place of a var declaration with implicit type inside a function.
  • every statement begins with a keyword (var, func, and so on) and so the := construct is not available outside a function.
package main

import "fmt"

/* Variables With Initializers */
var x = "Golang" 

func main() {
    /* Variables */
    var z,y int

    /* Variables With Initializers */
    var i, j int = 1, 2 

    /* Short variable declarations */
    k := 3 
    c, python, java := true, false, "no!" 

    fmt.Println(i, j, k, c, python, java, x, z, y)
}
Enter fullscreen mode Exit fullscreen mode

Output:

1 2 3 true false no! Golang 0 0
Enter fullscreen mode Exit fullscreen mode

Go's Basic Types

In Go, there are several basic types that represent fundamental data values. Here are the basic types in Go:

  1. Numeric Types:

    • int: Signed integers, which can be either 32 or 64 bits, depending on the platform.
    • int8, int16, int32, int64: Signed integers with specific bit sizes.
    • uint: Unsigned integers, which can be either 32 or 64 bits, depending on the platform.
    • uintptr: It is an unsigned integer type that is capable of holding the bit pattern of any pointer value. It is used primarily in low-level programming and for dealing with memory addresses.
    • uint8, uint16, uint32, uint64: Unsigned integers with specific bit sizes.
    • float32, float64: Floating-point numbers with single-precision and double-precision, respectively.
    • complex64, complex128: Complex numbers with single-precision and double-precision, respectively.
  2. Boolean Type:

    • bool: Represents a boolean value, which can be either true or false.
  3. String Type:

    • string: Represents a sequence of characters.
  4. Character Type:

    • Go does not have a separate character type. Instead, individual characters are represented as rune, which is an alias for int32.
  5. Composite Type:

    • array: Fixed-size collection of elements of the same type.
    • slice: Dynamic-size sequence built on top of arrays.
    • map: Unordered collection of key-value pairs.
    • struct: User-defined composite type that groups together zero or more values with different types.
    • pointer: Represents the memory address of a value.
    • function: Functions can have their own types and can be assigned to variables or used as arguments or return types in other functions.
    • interface: Defines a set of methods that a type must implement to satisfy the interface.
  6. Special Types:

    • nil: Represents the absence of a value. Used for uninitialized variables, pointers without a value, or when a function returns no value.
package main

import (
    "fmt"
)

func main() {
    // Numeric Types
    var numInt int = 42
    var MaxInt uint64 = 1<<64 - 1
    var numFloat float64 = 3.14
    var numComplex complex128 = -5 + 12i

    // Boolean Type
    var flag bool = true

    // String Type
    var message string = "Hello, Go!"

    // Character Type (rune)
    var char rune = 'A'

    // Composite Types
    var arr [3]int = [3]int{1, 2, 3}
    var slice []int = []int{4, 5, 6}
    var mp map[string]int = map[string]int{"apple": 1, "banana": 2}
    var person struct {
        name string
        age  int
    } = struct {
        name string
        age  int
    }{"Sahil", 20}
    var ptr *int = &numInt
    var fn func() = func() {
        fmt.Println("This is a function")
    }
    var intf interface{} = "This is an interface"

    // Special Types
    var nilVal []int
    var uintptrVal uintptr

    // Printing the values
    fmt.Printf("Numeric Types:\nint: %d\nunit64: %v\nfloat: %f\ncomplex: %f\n\n", numInt, MaxInt, numFloat, numComplex)
    fmt.Printf("Boolean Type:\nbool: %v\n\n", flag)
    fmt.Printf("String Type:\nstring: %s\n\n", message)
    fmt.Printf("Character Type:\nrune: %c\n\n", char)
    fmt.Printf("Composite Types:\narray: %v\nslice: %v\nmap: %v\nstruct: %+v\npointer: %p\nfunction: %v\ninterface: %v\n\n",
        arr, slice, mp, person, ptr, fn, intf)
    fmt.Printf("Special Types:\nnil: %v\nuintptr: %v\n", nilVal, uintptrVal)
}
Enter fullscreen mode Exit fullscreen mode

Output:

Numeric Types:
int: 42
unit64: 18446744073709551615
float: 3.140000
complex: (-5.000000+12.000000i)

Boolean Type:
bool: true

String Type:
string: Hello, Go!

Character Type:
rune: A

Composite Types:
array: [1 2 3]
slice: [4 5 6]
map: map[apple:1 banana:2]
struct: {name:Sahil age:20}
pointer: 0xc00001c030
function: 0x482fa0
interface: This is an interface

Special Types:
nil: []
uintptr: 0
Enter fullscreen mode Exit fullscreen mode
  • Variables declared without an explicit initial value are given their zero value. The zero value is:
  • 0 for numeric types,
  • false for the boolean type, and
  • "" (the empty string) for strings.
  • Type conversion in Go allows you to convert a value of one type to another type
package main

import "fmt"
import "math"

func main() {
    /* Zero Values */
    var i int
    var f float64
    var b bool
    var s string
    fmt.Printf("Zero Value for int: %v\nZero Value for float64: %v\nZero Value for bool: %v\nZero Value for string: %q\n\n", i, f, b, s)

    /* Type Conversion */
    var x, y int = 3, 5
    fmt.Printf("x: %v y: %v\n",x,y)

    var a float64 = math.Sqrt(float64(x*x + y*y))
    fmt.Printf("a: %v\n",a)

    var z uint = uint(a);
    fmt.Printf("z: %v\n",z)
}
Enter fullscreen mode Exit fullscreen mode

Output:

Zero Value for int: 0
Zero Value for float64: 0
Zero Value for bool: false
Zero Value for string: ""

x: 3 y: 5
a: 5.830951894845301
z: 5
Enter fullscreen mode Exit fullscreen mode

Type Inference & Constants

  • Type inference is a feature in programming languages that allows the compiler or interpreter to automatically determine the data type of a variable based on its assigned value or usage
  • Constants are declared like variables, but with the const keyword.
  • Constants can be character, string, boolean, or numeric values. Constants cannot be declared using the := syntax.
package main

import "fmt"

const Pi = 3.14

func main() {
    var f uint64
    var n int = 42
    var s = "Hi! I am Sahil"
    l := 0.867 + 0.5i

    fmt.Printf("f is of type %T\n", f)
    fmt.Printf("n is of type %T\n", n)
    fmt.Printf("s is of type %T\n", s)
    fmt.Printf("l is of type %T\n", l)

    fmt.Println("Happy", Pi, "Day")
    const Truth = true
    fmt.Println("Go rules?", Truth)
}
Enter fullscreen mode Exit fullscreen mode

Output:

f is of type uint64
n is of type int
s is of type string
l is of type complex128
Happy 3.14 Day
Go rules? true
Enter fullscreen mode Exit fullscreen mode

Loops

Go has only one looping construct, the for loop.

The basic for loop has three components separated by semicolons:

  • the init statement: executed before the first iteration
  • the condition expression: evaluated before every iteration
  • the post statement: executed at the end of every iteration
  • The init statement will often be a short variable declaration, and the variables declared there are visible only in the scope of the for statement.
  • The loop will stop iterating once the boolean condition evaluates to false.
package main

import "fmt"

func main() {
    /* Basic Syntax of For Loop */
    sum1 := 0
    for i := 0; i < 10; i++ {
        sum1 += i
    }
    fmt.Println(sum1)

    /* For Continued */
    sum2 := 1
    for ; sum2 < 1000; {
        sum2 += sum2
    }
    fmt.Println(sum2)

    /* This is Same as While Loop */
    sum3 := 1
    for sum3 < 1000 {
        sum3 += sum3
    }
    fmt.Println(sum3)

    /* An Infinite Loop */
    for {
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:

timeout running program
45
1024
1024
Enter fullscreen mode Exit fullscreen mode

if & else

Go's if statements are like its for loops; the expression need not be surrounded by parentheses ( ) but the braces { } are required.

package main

import (
    "fmt"
    "math"
)

/* Basic syntax of if */
func sqrt(x float64) string {
    if x < 0 {
        return sqrt(-x) + "i"
    }
    return fmt.Sprint(math.Sqrt(x))
}

/* If with a short statement */
func pow(x, n, lim float64) float64 {
    if v := math.Pow(x, n); v < lim {
        return v
    }
    return lim
}

/* if & else */
func power(x, n, lim float64) float64 {
    if v := math.Pow(x, n); v < lim {
        fmt.Printf("%g < %g\n", v, lim)
        return v;
    } else {
        fmt.Printf("%g >= %g\n", v, lim)
    }
    // can't use v here, though
    return lim
}

func main() {

    fmt.Println(sqrt(2), sqrt(-4))

    fmt.Println(pow(3, 2, 10),pow(3, 3, 20))

    fmt.Println(power(3, 2, 10),power(3, 3, 20))

}
Enter fullscreen mode Exit fullscreen mode

Output:

1.4142135623730951 2i
9 20
9 < 10
27 >= 20
9 20
Enter fullscreen mode Exit fullscreen mode

Switch

A switch statement is a shorter way to write a sequence of if - else statements. It runs the first case whose value is equal to the condition expression.

package main

import (
    "fmt"
    "runtime"
)

func main() {
    fmt.Print("Go runs on ")
    fmt.Println(runtime.GOOS)
    switch os := runtime.GOOS; os {
    case "darwin":
        fmt.Println("OS X.")
    case "linux":
        fmt.Println("Linux.")
    default:
        // freebsd, openbsd,
        // plan9, windows...
        fmt.Printf("%s.\n", os)
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:

Go runs on linux
Linux.
Enter fullscreen mode Exit fullscreen mode
Switch Evaluation Order
package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println("When's Saturday?")
    today := time.Now().Weekday()
    fmt.Println(today, time.Saturday)
    switch time.Saturday {
    case today + 0:
        fmt.Println("Today.")
    case today + 1:
        fmt.Println("Tomorrow.")
    case today + 2:
        fmt.Println("In two days.")
    default:
        fmt.Println("Too far away.")
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:

When's Saturday?
Tuesday Saturday
Too far away.
Enter fullscreen mode Exit fullscreen mode
Switch With No Condition

Switch without a condition is the same as switch true

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.Now()
    fmt.Println(time.Now())
    switch {
    case t.Hour() < 12:
        fmt.Println("Good morning!")
    case t.Hour() < 17:
        fmt.Println("Good afternoon.")
    default:
        fmt.Println("Good evening.")
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:

2023-05-20 11:09:16.988733639 +0000 UTC m=+0.000047230
Good morning!
Enter fullscreen mode Exit fullscreen mode

Defer

In Go, the defer statement is used to schedule a function call to be executed later, typically just before the surrounding function returns. The defer statement allows you to specify cleanup or finalization actions that should be performed regardless of how the function exits, whether it's due to a return statement, an error, or a panic.

  • Deferred function calls are pushed onto a stack. When a function returns, its deferred calls are executed in last-in-first-out order.
package main

import "fmt"

func main() {
    defer fmt.Println("HY! I am Sahil")
    fmt.Println("I am Student")

    fmt.Println("counting")

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

    fmt.Println("done")
}
Enter fullscreen mode Exit fullscreen mode

Output:

I am Student
counting
done
9
8
7
6
5
4
3
2
1
0
HY! I am Sahil
Enter fullscreen mode Exit fullscreen mode
Thank you for diving into this chapter of the blog! We've covered a lot of ground, but the journey doesn't end here. The next chapter awaits, ready to take you further into the depths of our topic.
To continue reading and explore the next chapter, simply follow this link: Link to Next Chapter

Go, where semicolons are optional, but your frustration is mandatory. Embrace the challenge, for in the end, you'll appreciate the elegance it brings. Keep on gophering!✨😂

Top comments (1)

Collapse
 
utsavdesai26 profile image
Utsav Desai

Looking forward to diving into the world of Go syntax with this guide. Clear explanations are key for beginners like me. Eagerly waiting for Part 2!