Mastering Go: A Comprehensive Guide to Golang Syntax | Part - 1
Tags: go, beginners, microservices, programming
Published: 2023-05-20 11:20:13

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](https://go.dev/).
 - 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
 ```
 - 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!")
}
```
- 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
```
- 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
```
- 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 */
}
```

Output:

```
My favorite number is 90
```

#### 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))
}

```
Output:

```
Now you have 4 problems.
```

#### 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 */
}
```


#### 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))
}
```
Output:

```
150
250
```
- 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))
}
```
Output:

```
World Hello
7 10
```

#### 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)
}
```
Output:

```
1 2 3 true false no! Golang 0 0
```

#### 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)
}
```

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
```

- 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)
}
```
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
```

####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)
}
```

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
```

#### 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 {
	}
}
```

Output:

```
timeout running program
45
1024
1024
```

#### 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))
	
}
```

Output:

```
1.4142135623730951 2i
9 20
9 < 10
27 >= 20
9 20
```

#### 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)
	}
}
```
Output:

```
Go runs on linux
Linux.
```

#####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.")
	}
}
```
Output:

```
When's Saturday?
Tuesday Saturday
Too far away.
```
#####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.")
	}
}
```
Output:

```
2023-05-20 11:09:16.988733639 +0000 UTC m=+0.000047230
Good morning!
```
#### 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")
}
```
Output:

```
I am Student
counting
done
9
8
7
6
5
4
3
2
1
0
HY! I am Sahil
```

#####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](https://dev.to/sahil_4555/mastering-go-a-comprehensive-guide-to-golang-syntax-part-2-22km)

> _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!✨😂_