{"id":13619911,"url":"https://github.com/karanpratapsingh/learn-go","last_synced_at":"2025-05-16T19:06:15.161Z","repository":{"id":39377009,"uuid":"506916699","full_name":"karanpratapsingh/learn-go","owner":"karanpratapsingh","description":"Master the fundamentals and advanced features of the Go programming language","archived":false,"fork":false,"pushed_at":"2022-10-19T18:10:58.000Z","size":448,"stargazers_count":1012,"open_issues_count":0,"forks_count":129,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-04-12T17:49:40.573Z","etag":null,"topics":["course","go","golang","tech","tutorial"],"latest_commit_sha":null,"homepage":"https://leanpub.com/go","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/karanpratapsingh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/funding.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"custom":["buymeacoffee.com/karanps","paypal.me/karanps686"]}},"created_at":"2022-06-24T07:21:47.000Z","updated_at":"2025-04-12T11:44:49.000Z","dependencies_parsed_at":"2023-01-19T17:16:09.115Z","dependency_job_id":null,"html_url":"https://github.com/karanpratapsingh/learn-go","commit_stats":null,"previous_names":["karanpratapsingh/go-course"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karanpratapsingh%2Flearn-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karanpratapsingh%2Flearn-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karanpratapsingh%2Flearn-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karanpratapsingh%2Flearn-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/karanpratapsingh","download_url":"https://codeload.github.com/karanpratapsingh/learn-go/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254592368,"owners_count":22097011,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["course","go","golang","tech","tutorial"],"created_at":"2024-08-01T21:00:50.093Z","updated_at":"2025-05-16T19:06:15.141Z","avatar_url":"https://github.com/karanpratapsingh.png","language":"Go","funding_links":["buymeacoffee.com/karanps","paypal.me/karanps686"],"categories":["Go"],"sub_categories":[],"readme":"# Learn Go\n\nHey, welcome to the course, and thanks for learning Go. I hope this course provides a great learning experience.\n\n_This course is also available on my [website](https://karanpratapsingh.com/courses/go) and as an ebook on [leanpub](https://leanpub.com/go). Please leave a ⭐ as motivation if this was helpful!_\n\n# Table of contents\n\n- **Getting Started**\n\n  - [What is Go?](#what-is-go)\n  - [Why learn Go?](#why-learn-go)\n  - [Installation and Setup](#installation-and-setup)\n\n- **Chapter I**\n\n  - [Hello World](#hello-world)\n  - [Variables and Data Types](#variables-and-data-types)\n  - [String Formatting](#string-formatting)\n  - [Flow Control](#flow-control)\n  - [Functions](#functions)\n  - [Modules](#modules)\n  - [Packages](#packages)\n  - [Workspaces](#workspaces)\n  - [Useful Commands](#useful-commands)\n  - [Build](#build)\n\n- **Chapter II**\n\n  - [Pointers](#pointers)\n  - [Structs](#structs)\n  - [Methods](#methods)\n  - [Arrays and Slices](#arrays-and-slices)\n  - [Maps](#maps)\n\n- **Chapter III**\n\n  - [Interfaces](#interfaces)\n  - [Errors](#errors)\n  - [Panic and Recover](#panic-and-recover)\n  - [Testing](#testing)\n  - [Generics](#generics)\n\n- **Chapter IV**\n\n  - [Concurrency](#concurrency)\n  - [Goroutines](#goroutines)\n  - [Channels](#channels)\n  - [Select](#select)\n  - [Sync Package](#sync-package)\n  - [Advanced Concurrency Patterns](#advanced-concurrency-patterns)\n  - [Context](#context)\n\n- **Appendix**\n\n  - [Next Steps](#next-steps)\n  - [References](#references)\n\n# What is Go?\n\nGo (also known as _Golang_) is a programming language developed at Google in 2007 and open-sourced in 2009.\n\nIt focuses on simplicity, reliability, and efficiency. It was designed to combine the efficacy, speed, and safety of a statically typed and compiled language with the ease of programming of a dynamic language to make programming more fun again.\n\nIn a way, they wanted to combine the best parts of Python and C++ so that they can build reliable systems that can take advantage of multi-core processors.\n\n# Why learn Go?\n\nBefore we start this course, let us talk about why we should learn Go.\n\n## 1. Easy to learn\n\nGo is quite easy to learn and has a supportive and active community.\n\nAnd being a multipurpose language you can use it for things like backend development, cloud computing, and more recently, data science.\n\n## 2. Fast and Reliable\n\nWhich makes it highly suitable for distributed systems. Projects such as Kubernetes and Docker are written in Go.\n\n## 3. Simple yet powerful\n\nGo has just 25 keywords which makes it easy to read, write and maintain. The language itself is concise.\n\nBut don't be fooled by the simplicity, Go has several powerful features that we will later learn in the course.\n\n## 4. Career opportunities\n\nGo is growing fast and is being adopted by companies of any size. and with that, comes new high-paying job opportunities.\n\nI hope this made you excited about Go. Let's start this course.\n\n# Installation and Setup\n\nIn this tutorial, we will install Go and setup our code editor.\n\n## Download\n\nWe can install Go from the [downloads](https://go.dev/dl) section.\n\n![download](https://raw.githubusercontent.com/karanpratapsingh/portfolio/master/public/static/courses/go/getting-started/installation-and-setup/download.png)\n\n## Installation\n\n_These instructions are from the [official website](https://go.dev/doc/install)._\n\n### MacOS\n\n1. Open the package file you downloaded and follow the prompts to install Go.\n   The package installs the Go distribution to `/usr/local/go`. The package should put the `/usr/local/go/bin` directory in your `PATH` environment variable.\n   You may need to restart any open Terminal sessions for the change to take effect.\n\n2. Verify that you've installed Go by opening a command prompt and typing the following command:\n\n```\n$ go version\n```\n\n3. Confirm that the command prints the installed version of Go.\n\n### Linux\n\n1. Remove any previous Go installation by deleting the `/usr/local/go` folder (if it exists),\n   then extract the archive you just downloaded into `/usr/local`, creating a fresh Go tree in `/usr/local/go`:\n\n```\n$ rm -rf /usr/local/go \u0026\u0026 tar -C /usr/local -xzf go1.18.1.linux-amd64.tar.gz\n```\n\n_Note: You may need to run the command as root or through sudo._\n\n**Do not untar** the archive into an existing `/usr/local/go` tree. This is known to produce broken Go installations.\n\n2. Add `/usr/local/go/bin` to the PATH environment variable.\n   You can do this by adding the following line to your `$HOME/.profile` or `/etc/profile` (for a system-wide installation):\n\n```\nexport PATH=$PATH:/usr/local/go/bin\n```\n\n_Note: Changes made to a profile file may not apply until the next time you log into your computer. To apply the changes immediately, just run the shell commands directly or execute them from the profile using a command such as source `$HOME/.profile`._\n\n3. Verify that you've installed Go by opening a command prompt and typing the following command:\n\n```\n$ go version\n```\n\n4. Confirm that the command prints the installed version of Go.\n\n### Windows\n\n1. Open the MSI file you downloaded and follow the prompts to install Go.\n\nBy default, the installer will install Go to Program Files or Program Files (x86).\nYou can change the location as needed. After installing, you will need to close and reopen any open command prompts so that changes to the environment made by the installer are reflected at the command prompt.\n\n2. Verify that you've installed Go.\n   1. In Windows, click the Start menu.\n   2. In the menu's search box, type cmd, then press the Enter key.\n   3. In the Command Prompt window that appears, type the following command:\n\n```\n$ go version\n```\n\n3. Confirm that the command prints the installed version of Go.\n\n## VS Code\n\nIn this course, I will be using [VS Code](https://code.visualstudio.com) and you can download it from [here](https://code.visualstudio.com/download).\n\n![vscode](https://raw.githubusercontent.com/karanpratapsingh/portfolio/master/public/static/courses/go/getting-started/installation-and-setup/vscode.png)\n\n_Feel free to use any other code editor you prefer._\n\n### Extension\n\nMake sure to also install the [Go extension](https://code.visualstudio.com/docs/languages/go) which makes it easier to work with Go in VS Code.\n\n![extension](https://raw.githubusercontent.com/karanpratapsingh/portfolio/master/public/static/courses/go/getting-started/installation-and-setup/extension.png)\n\nThis is it for the installation and setup of Go, let's start the course and write our first hello world!\n\n# Hello World\n\nLet's write our first hello world program, we can start by initializing a module. For that, we can use the `go mod` command.\n\n```bash\n$ go mod init example\n```\n\nBut wait...what's a `module`? Don't worry we will discuss that soon! But for now, assume that the module is basically a collection of Go packages.\n\nMoving ahead, let's now create a `main.go` file and write a program that simply prints hello world.\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"Hello World!\")\n}\n```\n\n_If you're wondering, `fmt` is part of the Go standard library which is a set of core packages provided by the language._\n\n## Structure of a Go program\n\nNow, let's quickly break down what we did here, or rather the structure of a Go program.\n\nFirst, we defined a package such as `main`.\n\n```go\npackage main\n```\n\nThen, we have some imports.\n\n```go\nimport \"fmt\"\n```\n\nLast but not least, is our `main` function which acts as an entry point for our application, just like in other languages like C, Java, or C#.\n\n```go\nfunc main() {\n\t...\n}\n```\n\nRemember, the goal here is to keep a mental note, and later in the course, we'll learn about `functions`, `imports`, and other things in detail!\n\nFinally, to run our code, we can simply use `go run` command.\n\n```bash\n$ go run main.go\nHello World!\n```\n\nCongratulations, you just wrote your first Go program!\n\n# Variables and Data Types\n\nIn this tutorial, we will learn about variables. We will also learn about the different data types that Go provides us.\n\n## Variables\n\nLet's start with declaring a variable.\n\nThis is also known as declaration without initialization:\n\n```go\nvar foo string\n```\n\nDeclaration with initialization:\n\n```go\nvar foo string = \"Go is awesome\"\n```\n\nMultiple declarations:\n\n```go\nvar foo, bar string = \"Hello\", \"World\"\n// OR\nvar (\n\tfoo string = \"Hello\"\n\tbar string  = \"World\"\n)\n```\n\nType is omitted but will be inferred:\n\n```go\nvar foo = \"What's my type?\"\n```\n\nShorthand declaration, here we omit `var` keyword and type is always implicit. This is how we will see variables being declared most of the time. We also use the `:=` for declaration plus assignment.\n\n```go\nfoo := \"Shorthand!\"\n```\n\n_Note: Shorthand only works inside `function` bodies._\n\n## Constants\n\nWe can also declare constants with the `const` keyword. Which as the name suggests, are fixed values that cannot be reassigned.\n\n```go\nconst constant = \"This is a constant\"\n```\n\nIt is also important to note that, only constants can be assigned to other constants.\n\n```go\nconst a = 10\nconst b = a // ✅ Works\n\nvar a = 10\nconst b = a // ❌ a (variable of type int) is not constant (InvalidConstInit)\n```\n\n## Data Types\n\nPerfect! Now let's look at some basic data types available in Go. Starting with string.\n\n### String\n\nIn Go, a string is a sequence of bytes. They are declared either using double quotes or backticks which can span multiple lines.\n\n```go\nvar name string = \"My name is Go\"\n\nvar bio string = `I am statically typed.\n\t\t\t\t\t\t\t\t\tI was designed at Google.`\n```\n\n### Bool\n\nNext is `bool` which is used to store boolean values. It can have two possible values - `true` or `false`.\n\n```go\nvar value bool = false\nvar isItTrue bool = true\n```\n\n**Operators**\n\nWe can use the following operators on boolean types\n\n| Type     | Syntax          |\n| -------- | --------------- |\n| Logical  | `\u0026\u0026` `\\|\\|` `!` |\n| Equality | `==` `!=`       |\n\n### Numeric types\n\nNow, let's talk about numeric types.\n\n**Signed and Unsigned integers**\n\nGo has several built-in integer types of varying sizes for storing signed and unsigned integers\n\nThe size of the generic `int` and `uint` types are platform-dependent. This means it is 32-bits wide on a 32-bit system and 64-bits wide on a 64-bit system.\n\n```go\nvar i int = 404                     // Platform dependent\nvar i8 int8 = 127                   // -128 to 127\nvar i16 int16 = 32767               // -2^15 to 2^15 - 1\nvar i32 int32 = -2147483647         // -2^31 to 2^31 - 1\nvar i64 int64 = 9223372036854775807 // -2^63 to 2^63 - 1\n```\n\nSimilar to signed integers, we have unsigned integers.\n\n```go\nvar ui uint = 404                     // Platform dependent\nvar ui8 uint8 = 255                   // 0 to 255\nvar ui16 uint16 = 65535               // 0 to 2^16\nvar ui32 uint32 = 2147483647          // 0 to 2^32\nvar ui64 uint64 = 9223372036854775807 // 0 to 2^64\nvar uiptr uintptr                     // Integer representation of a memory address\n```\n\nIf you noticed, there's also an unsigned integer pointer `uintptr` type, which is an integer representation of a memory address. It is not recommended to use this, so we don't have to worry about it.\n\n**So which one should we use?**\n\nIt is recommended that whenever we need an integer value, we should just use `int` unless we have a specific reason to use a sized or unsigned integer type.\n\n**Byte and Rune**\n\nGolang has two additional integer types called `byte` and `rune` that are aliases for `uint8` and `int32` data types respectively.\n\n```go\ntype byte = uint8\ntype rune = int32\n```\n\n_A `rune` represents a unicode code point._\n\n```go\nvar b byte = 'a'\nvar r rune = '🍕'\n```\n\n**Floating point**\n\nNext, we have floating point types which are used to store numbers with a decimal component.\n\nGo has two floating point types `float32` and `float64`. Both type follows the IEEE-754 standard.\n\n_The default type for floating point values is float64._\n\n```go\nvar f32 float32 = 1.7812 // IEEE-754 32-bit\nvar f64 float64 = 3.1415 // IEEE-754 64-bit\n```\n\n**Operators**\n\nGo provides several operators for performing operations on numeric types.\n\n| Type                | Syntax                                                   |\n| ------------------- | -------------------------------------------------------- |\n| Arithmetic          | `+` `-` `*` `/` `%`                                      |\n| Comparison          | `==` `!=` `\u003c` `\u003e` `\u003c=` `\u003e=`                              |\n| Bitwise             | `\u0026` `\\|` `^` `\u003c\u003c` `\u003e\u003e`                                   |\n| Increment/Decrement | `++` `--`                                                |\n| Assignment          | `=` `+=` `-=` `*=` `/=` `%=` `\u003c\u003c=` `\u003e\u003e=` `\u0026=` `\\|=` `^=` |\n\n**Complex**\n\nThere are 2 complex types in Go, `complex128` where both real and imaginary parts are `float64` and `complex64` where real and imaginary parts are `float32`.\n\nWe can define complex numbers either using the built-in complex function or as literals.\n\n```go\nvar c1 complex128 = complex(10, 1)\nvar c2 complex64 = 12 + 4i\n```\n\n## Zero Values\n\nNow let's discuss zero values. So in Go, any variable declared without an explicit initial value is given its _zero value_. For example, let's declare some variables and see:\n\n```go\nvar i int\nvar f float64\nvar b bool\nvar s string\n\nfmt.Printf(\"%v %v %v %q\\n\", i, f, b, s)\n```\n\n```bash\n$ go run main.go\n0 0 false \"\"\n```\n\nSo, as we can see `int` and `float` are assigned as 0, `bool` as false, and `string` as an empty string. This is quite different from how other languages do it. For example, most languages initialize unassigned variables as null or undefined.\n\nThis is great, but what are those percent symbols in our `Printf` function? As you've already guessed, they are used for formatting and we will learn about them later.\n\n## Type Conversion\n\nMoving on, now that we have seen how data types work, let's see how to do type conversion.\n\n```go\ni := 42\nf := float64(i)\nu := uint(f)\n\nfmt.Printf(\"%T %T\", f, u)\n```\n\n```bash\n$ go run main.go\nfloat64 uint\n```\n\nAnd as we can see, it prints the type as `float64` and `uint`.\n\n_Note that this is different from parsing._\n\n## Alias types\n\nAlias types were introduced in Go 1.9. They allow developers to provide an alternate name for an existing type and use it interchangeably with the underlying type.\n\n```go\npackage main\n\nimport \"fmt\"\n\ntype MyAlias = string\n\nfunc main() {\n\tvar str MyAlias = \"I am an alias\"\n\n\tfmt.Printf(\"%T - %s\", str, str) // Output: string - I am an alias\n}\n```\n\n## Defined types\n\nLastly, we have defined types that unlike alias types do not use an equals sign.\n\n```go\npackage main\n\nimport \"fmt\"\n\ntype MyDefined string\n\nfunc main() {\n\tvar str MyDefined = \"I am defined\"\n\n\tfmt.Printf(\"%T - %s\", str, str) // Output: main.MyDefined - I am defined\n}\n```\n\n**But wait...what's the difference?**\n\nSo, defined types do more than just give a name to a type.\n\nIt first defines a new named type with an underlying type. However, this defined type is different from any other type, including its underline type.\n\nHence, it cannot be used interchangeably with the underlying type like alias types.\n\nIt's a bit confusing at first, hopefully, this example will make things clear.\n\n```go\npackage main\n\nimport \"fmt\"\n\ntype MyAlias = string\n\ntype MyDefined string\n\nfunc main() {\n\tvar alias MyAlias\n\tvar def MyDefined\n\n\t// ✅ Works\n\tvar copy1 string = alias\n\n\t// ❌ Cannot use def (variable of type MyDefined) as string value in variable\n\tvar copy2 string = def\n\n\tfmt.Println(copy1, copy2)\n}\n```\n\nAs we can see, we cannot use the defined type interchangeably with the underlying type, unlike _alias types_.\n\n# String Formatting\n\nIn this tutorial, we will learn about string formatting or sometimes also known as templating.\n\n`fmt` package contains lots of functions. So to save time, we will discuss the most frequently used functions. Let's start with `fmt.Print` inside our main function.\n\n```go\n...\n\nfmt.Print(\"What\", \"is\", \"your\", \"name?\")\nfmt.Print(\"My\", \"name\", \"is\", \"golang\")\n...\n```\n\n```bash\n$ go run main.go\nWhatisyourname?Mynameisgolang\n```\n\nAs we can see, `Print` does not format anything, it simply takes a string and prints it.\n\nNext, we have `Println` which is the same as `Print` but it adds a new line at the end and also inserts space between the arguments.\n\n```go\n...\n\nfmt.Println(\"What\", \"is\", \"your\", \"name?\")\nfmt.Println(\"My\", \"name\", \"is\", \"golang\")\n...\n```\n\n```bash\n$ go run main.go\nWhat is your name?\nMy name is golang\n```\n\nThat's much better!\n\nNext, we have `Printf` also known as _\"Print Formatter\"_, which allows us to format numbers, strings, booleans, and much more.\n\nLet's look at an example.\n\n```go\n...\nname := \"golang\"\n\nfmt.Println(\"What is your name?\")\nfmt.Printf(\"My name is %s\", name)\n...\n```\n\n```bash\n$ go run main.go\nWhat is your name?\nMy name is golang\n```\n\nAs we can see that `%s` was substituted with our `name` variable.\n\nBut the question is what is `%s` and what does it mean?\n\nSo, these are called _annotation verbs_ and they tell the function how to format the arguments. We can control things like width, types, and precision with these and there are lots of them. Here's a [cheatsheet](https://pkg.go.dev/fmt).\n\nNow, let's quickly look at some more examples. Here we will try to calculate a percentage and print it to the console.\n\n```go\n...\npercent := (7.0 / 9) * 100\nfmt.Printf(\"%f\", percent)\n...\n```\n\n```bash\n$ go run main.go\n77.777778\n```\n\nLet's say we want just `77.78` which is 2 points precision, we can do that as well by using `.2f`.\n\nAlso, to add an actual percent sign, we will need to _escape it_.\n\n```go\n...\npercent := (7.0 / 9) * 100\nfmt.Printf(\"%.2f %%\", percent)\n...\n```\n\n```bash\n$ go run main.go\n77.78 %\n```\n\nThis brings us to `Sprint`, `Sprintln`, and `Sprintf`. These are basically the same as the print functions, the only difference being they return the string instead of printing it.\n\nLet's take a look at an example.\n\n```go\n...\ns := fmt.Sprintf(\"hex:%x bin:%b\", 10 ,10)\nfmt.Println(s)\n...\n```\n\n```bash\n$ go run main.go\nhex:a bin:1010\n```\n\nSo, as we can see `Sprintf` formats our integer as hex or binary and returns it as a string.\n\nLastly, we have multiline string literals, which can be used like this.\n\n```go\n...\nmsg := `\nHello from\nmultiline\n`\n\nfmt.Println(msg)\n...\n```\n\nGreat! But this is just the tip of the iceberg...so make sure to check out the go doc for `fmt` package.\n\nFor those who are coming from C/C++ background, this should feel natural, but if you're coming from, let's say Python or JavaScript, this might be a little strange at first. But it is very powerful and you'll see this functionality used quite extensively.\n\n# Flow Control\n\nLet's talk about flow control, starting with if/else.\n\n## If/Else\n\nThis works pretty much the same as you expect but the expression doesn't need to be surrounded by parentheses `()`.\n\n```go\nfunc main() {\n\tx := 10\n\n\tif x \u003e 5 {\n\t\tfmt.Println(\"x is gt 5\")\n\t} else if x \u003e 10 {\n\t\tfmt.Println(\"x is gt 10\")\n\t} else {\n\t\tfmt.Println(\"else case\")\n\t}\n}\n```\n\n```bash\n$ go run main.go\nx is gt 5\n```\n\n### Compact if\n\nWe can also compact our if statements.\n\n```go\nfunc main() {\n\tif x := 10; x \u003e 5 {\n\t\tfmt.Println(\"x is gt 5\")\n\t}\n}\n```\n\n_Note: This pattern is quite common._\n\n## Switch\n\nNext, we have `switch` statement, which is often a shorter way to write conditional logic.\n\nIn Go, the switch case only runs the first case whose value is equal to the condition expression and not all the cases that follow. Hence, unlike other languages, `break` statement is automatically added at the end of each case.\n\nThis means that it evaluates cases from top to bottom, stopping when a case succeeds.\nLet's take a look at an example:\n\n```go\nfunc main() {\n\tday := \"monday\"\n\n\tswitch day {\n\tcase \"monday\":\n\t\tfmt.Println(\"time to work!\")\n\tcase \"friday\":\n\t\tfmt.Println(\"let's party\")\n\tdefault:\n\t\tfmt.Println(\"browse memes\")\n\t}\n}\n```\n\n```bash\n$ go run main.go\ntime to work!\n```\n\nSwitch also supports shorthand declaration like this.\n\n```go\n\tswitch day := \"monday\"; day {\n\tcase \"monday\":\n\t\tfmt.Println(\"time to work!\")\n\tcase \"friday\":\n\t\tfmt.Println(\"let's party\")\n\tdefault:\n\t\tfmt.Println(\"browse memes\")\n\t}\n```\n\nWe can also use the `fallthrough` keyword to transfer control to the next case even though the current case might have matched.\n\n```go\n\tswitch day := \"monday\"; day {\n\tcase \"monday\":\n\t\tfmt.Println(\"time to work!\")\n\t\tfallthrough\n\tcase \"friday\":\n\t\tfmt.Println(\"let's party\")\n\tdefault:\n\t\tfmt.Println(\"browse memes\")\n\t}\n```\n\nAnd if we run this, we'll see that after the first case matches the switch statement continues to the next case because of the `fallthrough` keyword.\n\n```bash\n$ go run main.go\ntime to work!\nlet's party\n```\n\nWe can also use it without any condition, which is the same as `switch true`.\n\n```go\nx := 10\n\nswitch {\n\tcase x \u003e 5:\n\t\tfmt.Println(\"x is greater\")\n\tdefault:\n\t\tfmt.Println(\"x is not greater\")\n}\n```\n\n## Loops\n\nNow, let's turn our attention toward loops.\n\nSo in Go, we only have one type of loop which is the `for` loop.\n\nBut it's incredibly versatile. Same as if statement, for loop, doesn't need any parenthesis `()` unlike other languages.\n\n### For loop\n\nLet's start with the basic `for` loop.\n\n```go\nfunc main() {\n\tfor i := 0; i \u003c 10; i++ {\n\t\tfmt.Println(i)\n\t}\n}\n```\n\nThe basic `for` loop has three components separated by semicolons:\n\n- **init statement**: which is executed before the first iteration.\n- **condition expression**: which is evaluated before every iteration.\n- **post statement**: which is executed at the end of every iteration.\n\n**Break and continue**\n\nAs expected, Go also supports both `break` and `continue` statements for loop control. Let's try a quick example:\n\n```go\nfunc main() {\n\tfor i := 0; i \u003c 10; i++ {\n\t\tif i \u003c 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfmt.Println(i)\n\n\t\tif i \u003e 5 {\n\t\t\tbreak\n\t\t}\n\t}\n\n\tfmt.Println(\"We broke out!\")\n}\n```\n\nSo, the `continue` statement is used when we want to skip the remaining portion of the loop, and `break` statement is used when we want to break out of the loop.\n\nAlso, Init and post statements are optional, hence we can make our `for` loop behave like a while loop as well.\n\n```go\nfunc main() {\n\ti := 0\n\n\tfor ;i \u003c 10; {\n\t\ti += 1\n\t}\n}\n```\n\n_Note: we can also remove the additional semi-colons to make it a little cleaner._\n\n### Forever loop\n\nLastly, If we omit the loop condition, it loops forever, so an infinite loop can be compactly expressed. This is also known as the forever loop.\n\n```go\nfunc main() {\n\tfor {\n\t\t// do stuff here\n\t}\n}\n```\n\n# Functions\n\nIn this tutorial, we will discuss how we work with functions in Go. So, let's start with a simple function declaration.\n\n## Simple declaration\n\n```go\nfunc myFunction() {}\n```\n\nAnd we can _call or execute_ it as follows.\n\n```go\n...\nmyFunction()\n...\n```\n\nLet's pass some parameters to it.\n\n```go\nfunc main() {\n\tmyFunction(\"Hello\")\n}\n\nfunc myFunction(p1 string) {\n\tfmt.Println(p1)\n}\n```\n\n```bash\n$ go run main.go\n```\n\nAs we can see it prints our message. We can also do a shorthand declaration if the consecutive parameters have the same type. For example:\n\n```go\nfunc myNextFunction(p1, p2 string) {}\n```\n\n## Returning the value\n\nNow let's also return a value.\n\n```go\nfunc main() {\n\ts := myFunction(\"Hello\")\n\tfmt.Println(s)\n}\n\nfunc myFunction(p1 string) string {\n\tmsg := fmt.Sprintf(\"%s function\", p1)\n\treturn msg\n}\n```\n\n### Multiple returns\n\nWhy return one value at a time, when we can do more? Go also supports multiple returns!\n\n```go\nfunc main() {\n\ts, i := myFunction(\"Hello\")\n\tfmt.Println(s, i)\n}\n\nfunc myFunction(p1 string) (string, int) {\n\tmsg := fmt.Sprintf(\"%s function\", p1)\n\treturn msg, 10\n}\n```\n\n### Named returns\n\nAnother cool feature is [named returns](https://go.dev/tour/basics/7), where return values can be named and treated as their own variables.\n\n```go\nfunc myFunction(p1 string) (s string, i int) {\n\ts = fmt.Sprintf(\"%s function\", p1)\n\ti = 10\n\n\treturn\n}\n```\n\nNotice how we added a `return` statement without any arguments, this is also known as _naked return_.\n\nI will say that, although this feature is interesting, please use it with care as this might reduce readability for larger functions.\n\n## Functions as values\n\nNext, let's talk about functions as values, in Go functions are first class and we can use them as values. So, let's clean up our function and try it out!\n\n```go\nfunc myFunction() {\n\tfn := func() {\n\t\tfmt.Println(\"inside fn\")\n\t}\n\n\tfn()\n}\n```\n\nWe can also simplify this by making `fn` an _anonymous function_.\n\n```go\nfunc myFunction() {\n\tfunc() {\n\t\tfmt.Println(\"inside fn\")\n\t}()\n}\n```\n\n_Notice how we execute it using the parenthesis at the end._\n\n## Closures\n\nWhy stop there? let's also return a function and hence create something called a closure. A simple definition can be that a closure is a function value that references variables from outside its body.\n\nClosures are lexically scoped, which means functions can access the values in scope when defining the function.\n\n```go\nfunc myFunction() func(int) int {\n\tsum := 0\n\n\treturn func(v int) int {\n\t\tsum += v\n\n\t\treturn sum\n\t}\n}\n```\n\n```go\n...\nadd := myFunction()\n\nadd(5)\nfmt.Println(add(10))\n...\n```\n\nAs we can see, we get a result of 15 as `sum` variable is _bound_ to the function. This is a very powerful concept and definitely, a must know.\n\n## Variadic Functions\n\nNow let's look at variadic functions, which are functions that can take zero or multiple arguments using the `...` ellipses operator.\n\nAn example here would be a function that can add a bunch of values.\n\n```go\nfunc main() {\n\tsum := add(1, 2, 3, 5)\n\tfmt.Println(sum)\n}\n\nfunc add(values ...int) int {\n\tsum := 0\n\n\tfor _, v := range values {\n\t\tsum += v\n\t}\n\n\treturn sum\n}\n```\n\nPretty cool huh? Also, don't worry about the `range` keyword, we will discuss it later in the course.\n\n_**Fun fact**: `fmt.Println` is a variadic function, that's how we were able to pass multiple values to it._\n\n## Init\n\nIn Go, `init` is a special lifecycle function that is executed before the `main` function.\n\nSimilar to `main`, the `init` function does not take any arguments nor returns any value. Let's see how it works with an example.\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc init() {\n\tfmt.Println(\"Before main!\")\n}\n\nfunc main() {\n\tfmt.Println(\"Running main\")\n}\n```\n\nAs expected, the `init` function was executed before the `main` function.\n\n```bash\n$ go run main.go\nBefore main!\nRunning main\n```\n\nUnlike `main`, there can be more than one `init` function in single or multiple files.\n\nFor multiple `init` in a single file, their processing is done in the order of their declaration, while `init` functions declared in multiple files are processed according to the lexicographic filename order.\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc init() {\n\tfmt.Println(\"Before main!\")\n}\n\nfunc init() {\n\tfmt.Println(\"Hello again?\")\n}\n\nfunc main() {\n\tfmt.Println(\"Running main\")\n}\n```\n\nAnd if we run this, we'll see the `init` functions were executed in the order they were declared.\n\n```bash\n$ go run main.go\nBefore main!\nHello again?\nRunning main\n```\n\nThe `init` function is optional and is particularly used for any global setup which might be essential for our program, such as establishing a database connection, fetching configuration files, setting up environment variables, etc.\n\n## Defer\n\nLastly, let's discuss the `defer` keyword, which lets us postpones the execution of a function until the surrounding function returns.\n\n```go\nfunc main() {\n\tdefer fmt.Println(\"I am finished\")\n\tfmt.Println(\"Doing some work...\")\n}\n```\n\nCan we use multiple defer functions? Absolutely, this brings us to what is known as _defer stack_. Let's take a look at an example:\n\n```go\nfunc main() {\n\tdefer fmt.Println(\"I am finished\")\n\tdefer fmt.Println(\"Are you?\")\n\n\tfmt.Println(\"Doing some work...\")\n}\n```\n\n```bash\n$ go run main.go\nDoing some work...\nAre you?\nI am finished\n```\n\nAs we can see, defer statements are stacked and executed in a _last in first out_ manner.\n\nSo, Defer is incredibly useful and is commonly used for doing cleanup or error handling.\n\nFunctions can also be used with generics but we will discuss them later in the course.\n\n# Modules\n\nIn this tutorial, we will learn about modules.\n\n## What are modules?\n\nSimply defined, A module is a collection of [Go packages](https://go.dev/ref/spec#Packages) stored in a file tree with a `go.mod` file at its root, provided the directory is _outside_ `$GOPATH/src`.\n\nGo modules were introduced in Go 1.11, which brings native support for versions and modules. Earlier, we needed the `GO111MODULE=on` flag to turn on the modules functionality when it was experimental. But now after Go 1.13 modules mode is the default for all development.\n\n**But wait, what is `GOPATH`?**\n\nWell, `GOPATH` is a variable that defines the root of your workspace and it contains the following folders:\n\n- **src**: contains Go source code organized in a hierarchy.\n- **pkg**: contains compiled package code.\n- **bin**: contains compiled binaries and executables.\n\n![gopath](https://raw.githubusercontent.com/karanpratapsingh/portfolio/master/public/static/courses/go/chapter-I/modules/gopath.png)\n\nLike earlier, let's create a new module using `go mod init` command which creates a new module and initializes the `go.mod` file that describes it.\n\n```bash\n$ go mod init example\n```\n\nThe important thing to note here is that a Go module can correspond to a Github repository as well if you plan to publish this module. For example:\n\n```bash\n$ go mod init example\n```\n\nNow, let's explore `go.mod` which is the file that defines the module's _module path_ and also the import path used for the root directory, and its _dependency requirements_.\n\n```go\nmodule \u003cname\u003e\n\ngo \u003cversion\u003e\n\nrequire (\n\t...\n)\n```\n\nAnd if we want to add a new dependency, we will use `go install` command:\n\n```bash\n$ go install github.com/rs/zerolog\n```\n\nAs we can see a `go.sum` file was also created. This file contains the expected [hashes](https://go.dev/cmd/go/#hdr-Module_downloading_and_verification) of the content of the new modules.\n\nWe can list all the dependencies using `go list` command as follows:\n\n```bash\n$ go list -m all\n```\n\nIf the dependency is not used, we can simply remove it using `go mod tidy` command:\n\n```bash\n$ go mod tidy\n```\n\nFinishing up our discussion on modules, let's also discuss vendoring.\n\nVendoring is the act of making your own copy of the 3rd party packages your project is using. Those copies are traditionally placed inside each project and then saved in the project repository.\n\nThis can be done through `go mod vendor` command.\n\nSo, let's reinstall the removed module using `go mod tidy`.\n\n```go\npackage main\n\nimport \"github.com/rs/zerolog/log\"\n\nfunc main() {\n\tlog.Info().Msg(\"Hello\")\n}\n```\n\n```bash\n$ go mod tidy\ngo: finding module for package github.com/rs/zerolog/log\ngo: found github.com/rs/zerolog/log in github.com/rs/zerolog v1.26.1\n```\n\n```bash\n$ go mod vendor\n```\n\nAfter the `go mod vendor` command is executed, a `vendor` directory will be created.\n\n```\n├── go.mod\n├── go.sum\n├── go.work\n├── main.go\n└── vendor\n    ├── github.com\n    │   └── rs\n    │       └── zerolog\n    │           └── ...\n    └── modules.txt\n```\n\n# Packages\n\nIn this tutorial, we will talk about packages.\n\n## What are packages?\n\nA package is nothing but a directory containing one or more Go source files, or other Go packages.\n\nThis means every Go source file must belong to a package and package declaration is done at top of every source file as follows.\n\n```go\npackage \u003cpackage_name\u003e\n```\n\nSo far, we've done everything inside of `package main`. By convention, executable programs (by that I mean the ones with the `main` package) are called _Commands_, others are simply called _Packages_.\n\nThe `main` package should also contain a `main()` function which is a special function that acts as the entry point of an executable program.\n\nLet's take a look at an example by creating our own package `custom` and adding some source files to it such as `code.go`.\n\n```go\npackage custom\n```\n\nBefore we proceed any further, we should talk about imports and exports. Just like other languages, go also has a concept of imports and exports but it's very elegant.\n\nBasically, any value (like a variable or function) can be exported and visible from other packages if they have been defined with an upper case identifier.\n\nLet's try an example in our `custom` package.\n\n```go\npackage custom\n\nvar value int = 10 // Will not be exported\nvar Value int = 20 // Will be exported\n```\n\nAs we can see lower case identifiers will not be exported and will be private to the package it's defined in. In our case the `custom` package.\n\nThat's great but how do we import or access it? Well, same as we've been doing so far unknowingly. Let's go to our `main.go` file and import our `custom` package.\n\nHere we can refer to it using the `module` we had initialized in our `go.mod` file earlier.\n\n```go\n---go.mod---\nmodule example\n\ngo 1.18\n\n---main.go--\npackage main\n\nimport \"example/custom\"\n\nfunc main() {\n\tcustom.Value\n}\n```\n\n_Notice how the package name is the last name of the import path._\n\nWe can import multiple packages as well like this.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"example/custom\"\n)\n\nfunc main() {\n\tfmt.Println(custom.Value)\n}\n```\n\nWe can also alias our imports to avoid collisions like this.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\tabcd \"example/custom\"\n)\n\nfunc main() {\n\tfmt.Println(abcd.Value)\n}\n```\n\n## External Dependencies\n\nIn Go, we are not only limited to working with local packages, we can also install external packages using `go install` command as we saw earlier.\n\nSo let's download a simple logging package `github.com/rs/zerolog/log`.\n\n```bash\n$ go install github.com/rs/zerolog\n```\n\n```go\npackage main\n\nimport (\n\t\"github.com/rs/zerolog/log\"\n\n\tabcd \"example/custom\"\n)\n\nfunc main() {\n\tlog.Print(abcd.Value)\n}\n```\n\nAlso, make sure to check out the go doc of packages you install, which is usually located in the project's readme file. go doc parses the source code and generates documentation in HTML format. Reference to It is usually located in readme files.\n\nLastly, I will add that, Go doesn't have a particular _\"folder structure\"_ convention, always try to organize your packages in a simple and intuitive way.\n\n# Workspaces\n\nIn this tutorial, we will learn about multi-module workspaces that were introduced in Go 1.18.\n\nWorkspaces allow us to work with multiple modules simultaneously without having to edit `go.mod` files for each module. Each module within a workspace is treated as a root module when resolving dependencies.\n\nTo understand this better, let's start by creating a `hello` module.\n\n```bash\n$ mkdir workspaces \u0026\u0026 cd workspaces\n$ mkdir hello \u0026\u0026 cd hello\n$ go mod init hello\n```\n\nFor demonstration purposes, I will add a simple `main.go` and install an example package.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"golang.org/x/example/stringutil\"\n)\n\nfunc main() {\n\tresult := stringutil.Reverse(\"Hello Workspace\")\n\tfmt.Println(result)\n}\n```\n\n```bash\n$ go get golang.org/x/example\ngo: downloading golang.org/x/example v0.0.0-20220412213650-2e68773dfca0\ngo: added golang.org/x/example v0.0.0-20220412213650-2e68773dfca0\n```\n\nAnd if we run this, we should see our output in reverse.\n\n```bash\n$ go run main.go\necapskroW olleH\n```\n\nThis is great, but what if we want to modify the `stringutil` module that our code depends on?\n\nUntil now, we had to do it using the `replace` directive in the `go.mod` file, but now let's see how we can use workspaces here.\n\nSo, let's create our workspace in the `workspaces` directory.\n\n```bash\n$ go work init\n```\n\nThis will create a `go.work` file.\n\n```bash\n$ cat go.work\ngo 1.18\n```\n\nWe will also add our `hello` module to the workspace.\n\n```bash\n$ go work use ./hello\n```\n\nThis should update the `go.work` file with a reference to our `hello` module.\n\n```go\ngo 1.18\n\nuse ./hello\n```\n\nNow, let's download and modify the `stringutil` package and update the `Reverse` function implementation.\n\n```bash\n$ git clone https://go.googlesource.com/example\nCloning into 'example'...\nremote: Total 204 (delta 39), reused 204 (delta 39)\nReceiving objects: 100% (204/204), 467.53 KiB | 363.00 KiB/s, done.\nResolving deltas: 100% (39/39), done.\n```\n\n`example/stringutil/reverse.go`\n\n```go\nfunc Reverse(s string) string {\n\treturn fmt.Sprintf(\"I can do whatever!! %s\", s)\n}\n```\n\nFinally, let's add `example` package to our workspace.\n\n```bash\n$ go work use ./example\n$ cat go.work\ngo 1.18\n\nuse (\n\t./example\n\t./hello\n)\n```\n\nPerfect, now if we run our `hello` module we will notice that the `Reverse` function has been modified.\n\n```bash\n$ go run hello\nI can do whatever!! Hello Workspace\n```\n\n_This is a very underrated feature from Go 1.18 but it is quite useful in certain circumstances._\n\n# Useful Commands\n\nDuring our module discussion, we discussed some go commands related to go modules, let's now discuss some other important commands.\n\nStarting with `go fmt`, which formats the source code and it's enforced by that language so that we can focus on how our code should work rather than how our code should look.\n\n```bash\n$ go fmt\n```\n\nThis might seem a little weird at first especially if you're coming from a javascript or python background like me but frankly, it's quite nice not to worry about linting rules.\n\nNext, we have `go vet` which reports likely mistakes in our packages.\n\nSo, if I go ahead and make a mistake in the syntax, and then run `go vet`.\n\nIt should notify me of the errors.\n\n```bash\n$ go vet\n```\n\nNext, we have `go env` which simply prints all the go environment information, we'll learn about some of these build-time variables later.\n\nLastly, we have `go doc` which shows documentation for a package or symbol, here's an example of the `fmt` package.\n\n```bash\n$ go doc -src fmt Printf\n```\n\nLet's use `go help` command to see what other commands are available.\n\n```bash\n$ go help\n```\n\nAs we can see, we have:\n\n`go fix` finds Go programs that use old APIs and rewrites them to use newer ones.\n\n`go generate` is usually used for code generation.\n\n`go install` compiles and installs packages and dependencies.\n\n`go clean` is used for cleaning files that are generated by compilers.\n\nSome other very important commands are `go build` and `go test` but we will learn about them in detail later in the course.\n\n# Build\n\nBuilding static binaries is one of the best features of Go which enables us to ship our code efficiently.\n\nWe can do this very easily using the `go build` command.\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"I am a binary!\")\n}\n```\n\n```bash\n$ go build\n```\n\nThis should produce a binary with the name of our module. For example, here we have `example`.\n\nWe can also specify the output.\n\n```bash\n$ go build -o app\n```\n\nNow to run this, we simply need to execute it.\n\n```bash\n$ ./app\nI am a binary!\n```\n\n_Yes, it's as simple as that!_\n\nNow, let's talk about some important build time variables, starting with:\n\n- `GOOS` and `GOARCH`\n\nThese environment variables help us build go programs for different [operating systems](https://en.wikipedia.org/wiki/Operating_system)\nand underlying processor [architectures](https://en.wikipedia.org/wiki/Microarchitecture).\n\nWe can list all the supported architecture using `go tool` command.\n\n```bash\n$ go tool dist list\nandroid/amd64\nios/amd64\njs/wasm\nlinux/amd64\nwindows/arm64\n.\n.\n.\n```\n\nHere's an example for building a windows executable from macOS!\n\n```bash\n$ GOOS=windows GOARCH=amd64 go build -o app.exe\n```\n\n- `CGO_ENABLED`\n\nThis variable allows us to configure [CGO](https://go.dev/blog/cgo), which is a way in Go to call C code.\n\nThis helps us to produce a [statically linked binary](https://en.wikipedia.org/wiki/Static_build) that works without any external dependencies.\n\nThis is quite helpful for, let's say when we want to run our go binaries in a docker container with minimum external dependencies.\n\nHere's an example of how to use it:\n\n```bash\n$ CGO_ENABLED=0 go build -o app\n```\n\n# Pointers\n\nIn this tutorial, we will discuss pointers. So what are Pointers?\n\nSimply defined, a Pointer is a variable that is used to store the memory address of another variable.\n\n![pointers](https://raw.githubusercontent.com/karanpratapsingh/portfolio/master/public/static/courses/go/chapter-II/pointers/pointers.png)\n\nIt can be used like this:\n\n```go\nvar x *T\n```\n\nWhere `T` is the type such as `int`, `string`, `float`, and so on.\n\nLet's try a simple example and see it in action.\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar p *int\n\n\tfmt.Println(p)\n}\n```\n\n```bash\n$ go run main.go\nnil\n```\n\nHmm, this prints `nil`, but what is `nil`?\n\nSo nil is a predeclared identifier in Go that represents zero value for pointers, interfaces, channels, maps, and slices.\n\nThis is just like what we learned in the variables and datatypes section, where we saw that uninitialized `int` has a zero value of 0, a `bool` has false, and so on.\n\nOkay, now let's assign a value to the pointer.\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\ta := 10\n\n\tvar p *int = \u0026a\n\n\tfmt.Println(\"address:\", p)\n}\n```\n\nWe use the `\u0026` ampersand operator to refer to a variable's memory address.\n\n```bash\n$ go run main.go\n0xc0000b8000\n```\n\nThis must be the value of the memory address of the variable `a`.\n\n## Dereferencing\n\nWe can also use the `*` asterisk operator to retrieve the value stored in the variable that the pointer points to. This is also called **dereferencing**.\n\nFor example, we can access the value of the variable `a` through the pointer `p` using that `*` asterisk operator.\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\ta := 10\n\n\tvar p *int = \u0026a\n\n\tfmt.Println(\"address:\", p)\n\tfmt.Println(\"value:\", *p)\n}\n```\n\n```bash\n$ go run main.go\naddress: 0xc000018030\nvalue: 10\n```\n\nWe can not only access it but change it as well through the pointer.\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\ta := 10\n\n\tvar p *int = \u0026a\n\n\tfmt.Println(\"before\", a)\n\tfmt.Println(\"address:\", p)\n\n\t*p = 20\n\tfmt.Println(\"after:\", a)\n}\n```\n\n```bash\n$ go run main.go\nbefore 10\naddress: 0xc000192000\nafter: 20\n```\n\nI think this is pretty neat!\n\n## Pointers as function args\n\nPointers can also be used as arguments for a function when we need to pass some data by reference.\n\nHere's an example:\n\n```go\nmyFunction(\u0026a)\n...\n\nfunc myFunction(ptr *int) {}\n```\n\n## New function\n\nThere's also another way to initialize a pointer. We can use the `new` function which takes a type as an argument, allocates enough memory to accommodate a value of that type, and returns a pointer to it.\n\nHere's an example:\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tp := new(int)\n\t*p = 100\n\n\tfmt.Println(\"value\", *p)\n\tfmt.Println(\"address\", p)\n}\n```\n\n```bash\n$ go run main.go\nvalue 100\naddress 0xc000018030\n```\n\n## Pointer to a Pointer\n\nHere's an interesting idea...can we create a pointer to a pointer? The answer is yes! Yes, we can.\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tp := new(int)\n\t*p = 100\n\n\tp1 := \u0026p\n\n\tfmt.Println(\"P value\", *p, \" address\", p)\n\tfmt.Println(\"P1 value\", *p1, \" address\", p)\n\n\tfmt.Println(\"Dereferenced value\", **p1)\n}\n```\n\n```bash\n$ go run main.go\nP value 100  address 0xc0000be000\nP1 value 0xc0000be000  address 0xc0000be000\nDereferenced value 100\n```\n\n_Notice how the value of `p1` matches the address of `p`._\n\nAlso, it is important to know that pointers in Go do not support pointer arithmetic like in C or C++.\n\n```go\n\tp1 := p * 2 // Compiler Error: invalid operation\n```\n\nHowever, we can compare two pointers of the same type for equality using a `==` operator.\n\n```go\np := \u0026a\np1 := \u0026a\n\nfmt.Println(p == p1)\n```\n\n## But Why?\n\nThis brings us to the million-dollar question, why do we need pointers?\n\nWell, there's no definite answer for that, and pointers are just another useful feature that helps us mutate our data efficiently without copying a large amount of data.\n\nLastly, I will add that if you are coming from a language with no notion of pointers, don't panic and try to form a mental model of how pointers work.\n\n# Structs\n\nIn this tutorial, we will learn about structs.\n\nSo, a `struct` is a user-defined type that contains a collection of named fields. Basically, it is used to group related data together to form a single unit.\n\nIf you're coming from an objected-oriented background, think of structs as lightweight classes which that support composition but not inheritance.\n\n## Defining\n\nWe can define a `struct` like this:\n\n```go\ntype Person struct {}\n```\n\nWe use the `type` keyword to introduce a new type, followed by the name and then the `struct` keyword to indicate that we're defining a struct.\n\nNow, let's give it some fields:\n\n```go\ntype Person struct {\n\tFirstName string\n\tLastName  string\n\tAge       int\n}\n```\n\nAnd, if the fields have the same type, we can collapse them as well.\n\n```go\ntype Person struct {\n\tFirstName, LastName string\n\tAge                 int\n}\n```\n\n## Declaring and initializing\n\nNow that we have our struct, we can declare it the same as other datatypes.\n\n```go\nfunc main() {\n\tvar p1 Person\n\n\tfmt.Println(\"Person 1:\", p1)\n}\n```\n\n```bash\n$ go run main.go\nPerson 1: {  0}\n```\n\nAs we can see, all the struct fields are initialized with their zero values. So the `FirstName` and `LastName` are set to `\"\"` empty string and `Age` is set to 0.\n\nWe can also initialize it as _\"struct literal\"_.\n\n```go\nfunc main() {\n\tvar p1 Person\n\n\tfmt.Println(\"Person 1:\", p1)\n\n\tvar p2 = Person{FirstName: \"Karan\", LastName: \"Pratap Singh\", Age: 22}\n\n\tfmt.Println(\"Person 2:\", p2)\n}\n```\n\nFor readability, we can separate by new line but this will also require a trailing comma.\n\n```go\n\tvar p2 = Person{\n\t\tFirstName: \"Karan\",\n\t\tLastName:  \"Pratap Singh\",\n\t\tAge:       22,\n\t}\n```\n\n```bash\n$ go run main.go\nPerson 1: {  0}\nPerson 2: {Karan Pratap Singh 22}\n```\n\nWe can also initialize only a subset of fields.\n\n```go\nfunc main() {\n\tvar p1 Person\n\n\tfmt.Println(\"Person 1:\", p1)\n\n\tvar p2 = Person{\n\t\tFirstName: \"Karan\",\n\t\tLastName:  \"Pratap Singh\",\n\t\tAge:       22,\n\t}\n\n\tfmt.Println(\"Person 2:\", p2)\n\n\tvar p3 = Person{\n\t\tFirstName: \"Tony\",\n\t\tLastName:  \"Stark\",\n\t}\n\n\tfmt.Println(\"Person 3:\", p3)\n}\n```\n\n```bash\n$ go run main.go\nPerson 1: {  0}\nPerson 2: {Karan Pratap Singh 22}\nPerson 3: {Tony Stark 0}\n```\n\nAs we can see, the age field of person 3 has defaulted to the zero value.\n\n## Without field name\n\nGo structs also supports initialization without field names.\n\n```go\nfunc main() {\n\tvar p1 Person\n\n\tfmt.Println(\"Person 1:\", p1)\n\n\tvar p2 = Person{\n\t\tFirstName: \"Karan\",\n\t\tLastName:  \"Pratap Singh\",\n\t\tAge:       22,\n\t}\n\n\tfmt.Println(\"Person 2:\", p2)\n\n\tvar p3 = Person{\n\t\tFirstName: \"Tony\",\n\t\tLastName:  \"Stark\",\n\t}\n\n\tfmt.Println(\"Person 3:\", p3)\n\n\tvar p4 = Person{\"Bruce\", \"Wayne\"}\n\n\tfmt.Println(\"Person 4:\", p4)\n}\n```\n\nBut here's the catch, we will need to provide all the values during the initialization or it will fail.\n\n```bash\n$ go run main.go\n# command-line-arguments\n./main.go:30:27: too few values in Person{...}\n```\n\n```go\n\tvar p4 = Person{\"Bruce\", \"Wayne\", 40}\n\n\tfmt.Println(\"Person 4:\", p4)\n```\n\nWe can also declare an anonymous struct.\n\n```go\nfunc main() {\n\tvar p1 Person\n\n\tfmt.Println(\"Person 1:\", p1)\n\n\tvar p2 = Person{\n\t\tFirstName: \"Karan\",\n\t\tLastName:  \"Pratap Singh\",\n\t\tAge:       22,\n\t}\n\n\tfmt.Println(\"Person 2:\", p2)\n\n\tvar p3 = Person{\n\t\tFirstName: \"Tony\",\n\t\tLastName:  \"Stark\",\n\t}\n\n\tfmt.Println(\"Person 3:\", p3)\n\n\tvar p4 = Person{\"Bruce\", \"Wayne\", 40}\n\n\tfmt.Println(\"Person 4:\", p4)\n\n\tvar a = struct {\n\t\tName string\n\t}{\"Golang\"}\n\n\tfmt.Println(\"Anonymous:\", a)\n}\n```\n\n## Accessing fields\n\nLet's clean up our example a bit and see how we can access individual fields.\n\n```go\nfunc main() {\n\tvar p = Person{\n\t\tFirstName: \"Karan\",\n\t\tLastName:  \"Pratap Singh\",\n\t\tAge:       22,\n\t}\n\n\tfmt.Println(\"FirstName\", p.FirstName)\n}\n```\n\nWe can also create a pointer to structs as well.\n\n```go\nfunc main() {\n\tvar p = Person{\n\t\tFirstName: \"Karan\",\n\t\tLastName:  \"Pratap Singh\",\n\t\tAge:       22,\n\t}\n\n\tptr := \u0026p\n\n\tfmt.Println((*ptr).FirstName)\n\tfmt.Println(ptr.FirstName)\n}\n```\n\nBoth statements are equal as in Go we don't need to explicitly dereference the pointer. We can also use the built-in `new` function.\n\n```go\nfunc main() {\n\tp := new(Person)\n\n\tp.FirstName = \"Karan\"\n\tp.LastName = \"Pratap Singh\"\n\tp.Age = 22\n\n\tfmt.Println(\"Person\", p)\n}\n```\n\n```bash\n$ go run main.go\nPerson \u0026{Karan Pratap Singh 22}\n```\n\nAs a side note, two structs are equal if all their corresponding fields are equal as well.\n\n```go\nfunc main() {\n\tvar p1 = Person{\"a\", \"b\", 20}\n\tvar p2 = Person{\"a\", \"b\", 20}\n\n\tfmt.Println(p1 == p2)\n}\n```\n\n```bash\n$ go run main.go\ntrue\n```\n\n## Exported fields\n\nNow let's learn what is exported and unexported fields in a struct. Same as the rules for variables and functions, if a struct field is declared with a lower case identifier, it will not be exported and only be visible to the package it is defined in.\n\n```go\ntype Person struct {\n\tFirstName, LastName  string\n\tAge                  int\n\tzipCode              string\n}\n```\n\nSo, the `zipCode` field won't be exported. Also, the same goes for the `Person` struct, if we rename it as `person`, it won't be exported as well.\n\n```go\ntype person struct {\n\tFirstName, LastName  string\n\tAge                  int\n\tzipCode              string\n}\n```\n\n## Embedding and composition\n\nAs we discussed earlier, Go doesn't necessarily support inheritance, but we can do something similar with embedding.\n\n```go\ntype Person struct {\n\tFirstName, LastName  string\n\tAge                  int\n}\n\ntype SuperHero struct {\n\tPerson\n\tAlias string\n}\n```\n\nSo, our new struct will have all the properties of the original struct. And it should behave the same as our normal struct.\n\n```go\nfunc main() {\n\ts := SuperHero{}\n\n\ts.FirstName = \"Bruce\"\n\ts.LastName = \"Wayne\"\n\ts.Age = 40\n\ts.Alias = \"batman\"\n\n\tfmt.Println(s)\n}\n```\n\n```bash\n$ go run main.go\n{{Bruce Wayne 40} batman}\n```\n\nHowever, this is usually not recommended and in most cases, composition is preferred. So rather than embedding, we will just define it as a normal field.\n\n```go\ntype Person struct {\n\tFirstName, LastName  string\n\tAge                  int\n}\n\ntype SuperHero struct {\n\tPerson Person\n\tAlias  string\n}\n```\n\nHence, we can rewrite our example with composition as well.\n\n```go\nfunc main() {\n\tp := Person{\"Bruce\", \"Wayne\", 40}\n\ts := SuperHero{p, \"batman\"}\n\n\tfmt.Println(s)\n}\n```\n\n```bash\n$ go run main.go\n{{Bruce Wayne 40} batman}\n```\n\nAgain, there is no right or wrong here, but nonetheless, embedding comes in handy sometimes.\n\n## Struct tags\n\nA struct tag is just a tag that allows us to attach metadata information to the field which can be used for custom behavior using the `reflect` package.\n\nLet's learn how we can define struct tags.\n\n```go\ntype Animal struct {\n\tName    string `key:\"value1\"`\n\tAge     int    `key:\"value2\"`\n}\n```\n\nYou will often find tags in encoding packages, such as XML, JSON, YAML, ORMs, and Configuration management.\n\nHere's a tags example for the JSON encoder.\n\n```go\ntype Animal struct {\n\tName    string `json:\"name\"`\n\tAge     int    `json:\"age\"`\n}\n```\n\n## Properties\n\nFinally, let's discuss the properties of structs.\n\nStructs are value types. When we assign one `struct` variable to another, a new copy of the `struct` is created and assigned.\n\nSimilarly, when we pass a `struct` to another function, the function gets its own copy of the `struct`.\n\n```go\npackage main\n\nimport \"fmt\"\n\ntype Point struct {\n\tX, Y float64\n}\n\nfunc main() {\n\tp1 := Point{1, 2}\n\tp2 := p1 // Copy of p1 is assigned to p2\n\n\tp2.X = 2\n\n\tfmt.Println(p1) // Output: {1 2}\n\tfmt.Println(p2) // Output: {2 2}\n}\n```\n\nEmpty struct occupies zero bytes of storage.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"unsafe\"\n)\n\nfunc main() {\n\tvar s struct{}\n\tfmt.Println(unsafe.Sizeof(s)) // Output: 0\n}\n```\n\n# Methods\n\nLet's talk about methods, sometimes also known as function receivers.\n\nTechnically, Go is not an object-oriented programming language. It doesn't have classes, objects, and inheritance.\n\nHowever, Go has types. And, you can define **methods** on types.\n\nA method is nothing but a function with a special _receiver_ argument. Let's see how we can declare methods.\n\n```go\nfunc (variable T) Name(params) (returnTypes) {}\n```\n\nThe _receiver_ argument has a name and a type. It appears between the `func` keyword and the method name.\n\nFor example, let's define a `Car` struct.\n\n```go\ntype Car struct {\n\tName string\n\tYear int\n}\n```\n\nNow, let us define a method like `IsLatest` which will tell us if a car was manufactured within the last 5 years.\n\n```go\nfunc (c Car) IsLatest() bool {\n\treturn c.Year \u003e= 2017\n}\n```\n\nAs you can see, we can access the instance of `Car` using the receiver variable `c`. I like to think of it as `this` keyword from the object-oriented world.\n\nNow we should be able to call this method after we initialize our struct, just like we do with classes in other languages.\n\n```go\nfunc main() {\n\tc := Car{\"Tesla\", 2021}\n\n\tfmt.Println(\"IsLatest\", c.IsLatest())\n}\n```\n\n## Methods with Pointer receivers\n\nAll the examples that we saw previously had a value receiver.\n\nWith a value receiver, the method operates on a copy of the value passed to it. Therefore, any modifications done to the receiver inside the methods are not visible to the caller.\n\nFor example, let's make another method called `UpdateName` which will update the name of the `Car`.\n\n```go\nfunc (c Car) UpdateName(name string) {\n\tc.Name = name\n}\n```\n\nNow, let's run this.\n\n```go\nfunc main() {\n\tc := Car{\"Tesla\", 2021}\n\n\tc.UpdateName(\"Toyota\")\n\tfmt.Println(\"Car:\", c)\n}\n```\n\n```bash\n$ go run main.go\nCar: {Tesla 2021}\n```\n\nSeems like the name wasn't updated, so now let's switch our receiver to pointer type and try again.\n\n```go\nfunc (c *Car) UpdateName(name string) {\n\tc.Name = name\n}\n```\n\n```bash\n$ go run main.go\nCar: {Toyota 2021}\n```\n\nAs expected, methods with pointer receivers can modify the value to which the receiver points. Such modifications are visible to the caller of the method as well.\n\n## Properties\n\nLet's also see some properties of the methods!\n\n- Go is smart enough to interpret our function call correctly, and hence, pointer receiver method calls are just syntactic sugar provided by Go for convenience.\n\n```go\n(\u0026c).UpdateName(...)\n```\n\n- We can omit the variable part of the receiver as well if we're not using it.\n\n```go\nfunc (Car) UpdateName(...) {}\n```\n\n- Methods are not limited to structs but can also be used with non-struct types as well.\n\n```go\npackage main\n\nimport \"fmt\"\n\ntype MyInt int\n\nfunc (i MyInt) isGreater(value int) bool {\n\treturn i \u003e MyInt(value)\n}\n\nfunc main() {\n\ti := MyInt(10)\n\n\tfmt.Println(i.isGreater(5))\n}\n```\n\n## Why methods instead of functions?\n\nSo the question is, why use methods instead of functions?\n\nAs always, there's no particular answer for this, and in no way one is better than the other. Instead, they should be used appropriately when the situation arrives.\n\nOne thing I can think of right now is that methods can help us avoid naming conflicts.\n\nSince a method is tied to a particular type, we can have the same method names for multiple receivers.\n\nBut in the end, it might just come down to preference, such as _\"method calls are much easier to read and understand than function calls\"_ or the other way around.\n\n# Arrays and Slices\n\nIn this tutorial, we will learn about arrays and slices in Go.\n\n## Arrays\n\n### What is an array?\n\nAn array is a fixed-size collection of elements of the same type. The elements of the array are stored sequentially and can be accessed using their `index`.\n\n![array](https://raw.githubusercontent.com/karanpratapsingh/portfolio/master/public/static/courses/go/chapter-II/arrays-and-slices/array.png)\n\n### Declaration\n\nWe can declare an array as follows:\n\n```go\nvar a [n]T\n```\n\nHere, `n` is the length and `T` can be any type like integer, string, or user-defined structs.\n\nNow, let's declare an array of integers with length 4 and print it.\n\n```go\nfunc main() {\n\tvar arr [4]int\n\n\tfmt.Println(arr)\n}\n```\n\n```bash\n$ go run main.go\n[0 0 0 0]\n```\n\nBy default, all the array elements are initialized with the zero value of the corresponding array type.\n\n### Initialization\n\nWe can also initialize an array using an array literal.\n\n```go\nvar a [n]T = [n]T{V1, V2, ... Vn}\n```\n\n```go\nfunc main() {\n\tvar arr = [4]int{1, 2, 3, 4}\n\n\tfmt.Println(arr)\n}\n```\n\n```bash\n$ go run main.go\n[1 2 3 4]\n```\n\nWe can even do a shorthand declaration.\n\n```go\n...\narr := [4]int{1, 2, 3, 4}\n```\n\n### Access\n\nAnd similar to other languages, we can access the elements using the `index` as they're stored sequentially.\n\n```go\nfunc main() {\n\tarr := [4]int{1, 2, 3, 4}\n\n\tfmt.Println(arr[0])\n}\n```\n\n```bash\n$ go run main.go\n1\n```\n\n### Iteration\n\nNow, let's talk about iteration.\n\nSo, there are multiple ways to iterate over arrays.\n\nThe first one is using the for loop with the `len` function which gives us the length of the array.\n\n```go\nfunc main() {\n\tarr := [4]int{1, 2, 3, 4}\n\n\tfor i := 0; i \u003c len(arr); i++ {\n\t\tfmt.Printf(\"Index: %d, Element: %d\\n\", i, arr[i])\n\t}\n}\n```\n\n```bash\n$ go run main.go\nIndex: 0, Element: 1\nIndex: 1, Element: 2\nIndex: 2, Element: 3\nIndex: 3, Element: 4\n```\n\nAnother way is to use the `range` keyword with the `for` loop.\n\n```go\nfunc main() {\n\tarr := [4]int{1, 2, 3, 4}\n\n\tfor i, e := range arr {\n\t\tfmt.Printf(\"Index: %d, Element: %d\\n\", i, e)\n\t}\n}\n```\n\n```bash\n$ go run main.go\nIndex: 0, Element: 1\nIndex: 1, Element: 2\nIndex: 2, Element: 3\nIndex: 3, Element: 4\n```\n\nAs we can see, our example works the same as before.\n\nBut the range keyword is quite versatile and can be used in multiple ways.\n\n```go\nfor i, e := range arr {} // Normal usage of range\n\nfor _, e := range arr {} // Omit index with _ and use element\n\nfor i := range arr {} // Use index only\n\nfor range arr {} // Simply loop over the array\n```\n\n### Multi dimensional\n\nAll the arrays that we created so far are one-dimensional. We can also create multi-dimensional arrays in Go.\n\nLet's take a look at an example:\n\n```go\nfunc main() {\n\tarr := [2][4]int{\n\t\t{1, 2, 3, 4},\n\t\t{5, 6, 7, 8},\n\t}\n\n\tfor i, e := range arr {\n\t\tfmt.Printf(\"Index: %d, Element: %d\\n\", i, e)\n\t}\n}\n```\n\n```bash\n$ go run main.go\nIndex: 0, Element: [1 2 3 4]\nIndex: 1, Element: [5 6 7 8]\n```\n\nWe can also let the compiler infer the length of the array by using `...` ellipses instead of the length.\n\n```go\nfunc main() {\n\tarr := [...][4]int{\n\t\t{1, 2, 3, 4},\n\t\t{5, 6, 7, 8},\n\t}\n\n\tfor i, e := range arr {\n\t\tfmt.Printf(\"Index: %d, Element: %d\\n\", i, e)\n\t}\n}\n```\n\n```bash\n$ go run main.go\nIndex: 0, Element: [1 2 3 4]\nIndex: 1, Element: [5 6 7 8]\n```\n\n### Properties\n\nNow let's talk about some properties of arrays.\n\nThe array's length is part of its type. So, the array `a` and `b` are completely distinct types, and we cannot assign one to the other.\n\nThis also means that we cannot resize an array, because resizing an array would mean changing its type.\n\n```go\npackage main\n\nfunc main() {\n\tvar a = [4]int{1, 2, 3, 4}\n\tvar b [2]int = a // Error, cannot use a (type [4]int) as type [2]int in assignment\n}\n```\n\nArrays in Go are value types unlike other languages like C, C++, and Java where arrays are reference types.\n\nThis means that when we assign an array to a new variable or pass an array to a function, the entire array is copied.\n\nSo, if we make any changes to this copied array, the original array won't be affected and will remain unchanged.\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar a = [7]string{\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"}\n\tvar b = a // Copy of a is assigned to b\n\n\tb[0] = \"Monday\"\n\n\tfmt.Println(a) // Output: [Mon Tue Wed Thu Fri Sat Sun]\n\tfmt.Println(b) // Output: [Monday Tue Wed Thu Fri Sat Sun]\n}\n```\n\n## Slices\n\nI know what you're thinking, arrays are useful but a bit inflexible due to the limitation caused by their fixed size.\n\nThis brings us to Slice, so what is a slice?\n\nA Slice is a segment of an array. Slices build on arrays and provide more power, flexibility, and convenience.\n\n![slice](https://raw.githubusercontent.com/karanpratapsingh/portfolio/master/public/static/courses/go/chapter-II/arrays-and-slices/slice.png)\n\nA slice consists of three things:\n\n- A pointer reference to an underlying array.\n- The length of the segment of the array that the slice contains.\n- And, the capacity, which is the maximum size up to which the segment can grow.\n\nJust like `len` function, we can determine the capacity of a slice using the built-in `cap` function. Here's an example:\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\ta := [5]int{20, 15, 5, 30, 25}\n\n\ts := a[1:4]\n\n\t// Output: Array: [20 15 5 30 25], Length: 5, Capacity: 5\n\tfmt.Printf(\"Array: %v, Length: %d, Capacity: %d\\n\", a, len(a), cap(a))\n\n\t// Output: Slice [15 5 30], Length: 3, Capacity: 4\n\tfmt.Printf(\"Slice: %v, Length: %d, Capacity: %d\", s, len(s), cap(s))\n}\n```\n\nDon't worry, we are going to discuss everything shown here in detail.\n\n### Declaration\n\nLet's see how we can declare a slice.\n\n```go\nvar s []T\n```\n\nAs we can see, we don't need to specify any length. Let's declare a slice of integers and see how it works.\n\n```go\nfunc main() {\n\tvar s []string\n\n\tfmt.Println(s)\n\tfmt.Println(s == nil)\n}\n```\n\n```bash\n$ go run main.go\n[]\ntrue\n```\n\nSo, unlike arrays, the zero value of a slice is `nil`.\n\n### Initialization\n\nThere are multiple ways to initialize our slice. One way is to use the built-in `make` function.\n\n```go\nmake([]T, len, cap) []T\n```\n\n```go\nfunc main() {\n\tvar s = make([]string, 0, 0)\n\n\tfmt.Println(s)\n}\n```\n\n```bash\n$ go run main.go\n[]\n```\n\nSimilar to arrays, we can use the slice literal to initialize our slice.\n\n```go\nfunc main() {\n\tvar s = []string{\"Go\", \"TypeScript\"}\n\n\tfmt.Println(s)\n}\n```\n\n```bash\n$ go run main.go\n[Go TypeScript]\n```\n\nAnother way is to create a slice from an array. Since a slice is a segment of an array, we can create a slice from index `low` to `high` as follows.\n\n```go\na[low:high]\n```\n\n```go\nfunc main() {\n\tvar a = [4]string{\n\t\t\"C++\",\n\t\t\"Go\",\n\t\t\"Java\",\n\t\t\"TypeScript\",\n\t}\n\n\ts1 := a[0:2] // Select from 0 to 2\n\ts2 := a[:3]  // Select first 3\n\ts3 := a[2:]  // Select last 2\n\n\tfmt.Println(\"Array:\", a)\n\tfmt.Println(\"Slice 1:\", s1)\n\tfmt.Println(\"Slice 2:\", s2)\n\tfmt.Println(\"Slice 3:\", s3)\n}\n```\n\n```bash\n$ go run main.go\nArray: [C++ Go Java TypeScript]\nSlice 1: [C++ Go]\nSlice 2: [C++ Go Java]\nSlice 3: [Java TypeScript]\n```\n\n_Missing low index implies 0 and missing high index implies the length of the underlying array (`len(a)`)._\n\nThe thing to note here is we can create a slice from other slices too and not just arrays.\n\n```go\nvar a = []string{\n\t\"C++\",\n\t\"Go\",\n\t\"Java\",\n\t\"TypeScript\",\n}\n```\n\n### Iteration\n\nWe can iterate over a slice in the same way you iterate over an array, by using the for loop with either `len` function or `range` keyword.\n\n### Functions\n\nSo now, let's talk about built-in slice functions provided in Go.\n\n**copy**\n\nThe `copy()` function copies elements from one slice to another. It takes 2 slices, a destination, and a source. It also returns the number of elements copied.\n\n```go\nfunc copy(dst, src []T) int\n```\n\nLet's see how we can use it.\n\n```go\nfunc main() {\n\ts1 := []string{\"a\", \"b\", \"c\", \"d\"}\n\ts2 := make([]string, len(s1))\n\n\te := copy(s2, s1)\n\n\tfmt.Println(\"Src:\", s1)\n\tfmt.Println(\"Dst:\", s2)\n\tfmt.Println(\"Elements:\", e)\n}\n```\n\n```bash\n$ go run main.go\nSrc: [a b c d]\nDst: [a b c d]\nElements: 4\n```\n\nAs expected, our 4 elements from the source slice were copied to the destination slice.\n\n**append**\n\nNow, let's look at how we can append data to our slice using the built-in `append` function which appends new elements at the end of a given slice.\n\nIt takes a slice and a variable number of arguments. It then returns a new slice containing all the elements.\n\n```go\nappend(slice []T, elems ...T) []T\n```\n\nLet's try it in an example by appending elements to our slice.\n\n```go\nfunc main() {\n\ts1 := []string{\"a\", \"b\", \"c\", \"d\"}\n\n\ts2 := append(s1, \"e\", \"f\")\n\n\tfmt.Println(\"s1:\", s1)\n\tfmt.Println(\"s2:\", s2)\n}\n```\n\n```bash\n$ go run main.go\ns1: [a b c d]\ns2: [a b c d e f]\n```\n\nAs we can see, the new elements were appended and a new slice was returned.\n\nBut if the given slice doesn't have sufficient capacity for the new elements then a new underlying array is allocated with a bigger capacity.\n\nAll the elements from the underlying array of the existing slice are copied to this new array, and then the new elements are appended.\n\n### Properties\n\nFinally, let's discuss some properties of slices.\n\nSlices are reference types, unlike arrays.\n\nThis means modifying the elements of a slice will modify the corresponding elements in the referenced array.\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\ta := [7]string{\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"}\n\n\ts := a[0:2]\n\n\ts[0] = \"Sun\"\n\n\tfmt.Println(a) // Output: [Sun Tue Wed Thu Fri Sat Sun]\n\tfmt.Println(s) // Output: [Sun Tue]\n}\n```\n\nSlices can be used with variadic types as well.\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tvalues := []int{1, 2, 3}\n\tsum := add(values...)\n\tfmt.Println(sum)\n}\n\nfunc add(values ...int) int {\n\tsum := 0\n\tfor _, v := range values {\n\t\tsum += v\n\t}\n\n\treturn sum\n}\n```\n\n# Maps\n\nSo, Go provides a built-in map type, and we'll learn how to use it.\n\nBut, the question is what are maps? And why do we need them?\n\n![maps](https://raw.githubusercontent.com/karanpratapsingh/portfolio/master/public/static/courses/go/chapter-II/maps/maps.png)\n\nWell, A map is an unordered collection of key-value pairs. It maps keys to values. The keys are unique within a map while the values may not be.\n\nIt is used for fast lookups, retrieval, and deletion of data based on keys. It is one of the most used data structures.\n\n## Declaration\n\nLet's start with the declaration.\n\nA map is declared using the following syntax:\n\n```go\nvar m map[K]V\n```\n\nWhere `K` is the key type and `V` is the value type.\n\nFor example, here's how we can declare a map of `string` keys to `int` values.\n\n```go\nfunc main() {\n\tvar m map[string]int\n\n\tfmt.Println(m)\n}\n```\n\n```bash\n$ go run main.go\nnil\n```\n\nAs we can see, the zero value of a map is `nil`.\n\nA `nil` map has no keys. Moreover, any attempt to add keys to a `nil` map will result in a runtime error.\n\n## Initialization\n\nThere are multiple ways to initialize a map.\n\n**make function**\n\nWe can use the built-in `make` function, which allocates memory for referenced data types and initializes their underlying data structures.\n\n```go\nfunc main() {\n\tvar m = make(map[string]int)\n\n\tfmt.Println(m)\n}\n```\n\n```bash\n$ go run main.go\nmap[]\n```\n\n**map literal**\n\nAnother way is using a map literal.\n\n```go\nfunc main() {\n\tvar m = map[string]int{\n\t\t\"a\": 0,\n    \"b\": 1,\n\t}\n\n\tfmt.Println(m)\n}\n```\n\n_Note that the trailing comma is required._\n\n```bash\n$ go run main.go\nmap[a:0 b:1]\n```\n\nAs always, we can use our custom types as well.\n\n```go\ntype User struct {\n\tName string\n}\n\nfunc main() {\n\tvar m = map[string]User{\n\t\t\"a\": User{\"Peter\"},\n\t\t\"b\": User{\"Seth\"},\n\t}\n\n\tfmt.Println(m)\n}\n```\n\nWe can even remove the value type and Go will figure it out!\n\n```go\nvar m = map[string]User{\n\t\"a\": {\"Peter\"},\n\t\"b\": {\"Seth\"},\n}\n```\n\n```bash\n$ go run main.go\nmap[a:{Peter} b:{Seth}]\n```\n\n## Add\n\nNow, let's see how we can add a value to our map.\n\n```go\nfunc main() {\n\tvar m = map[string]User{\n\t\t\"a\": {\"Peter\"},\n\t\t\"b\": {\"Seth\"},\n\t}\n\n\tm[\"c\"] = User{\"Steve\"}\n\n\tfmt.Println(m)\n}\n```\n\n```bash\n$ go run main.go\nmap[a:{Peter} b:{Seth} c:{Steve}]\n```\n\n## Retrieve\n\nWe can also retrieve our values from the map using the key.\n\n```go\n...\nc := m[\"c\"]\nfmt.Println(\"Key c:\", c)\n```\n\n```bash\n$ go run main.go\nkey c: {Steve}\n```\n\n**What if we use a key that is not present in the map?**\n\n```go\n...\nd := m[\"d\"]\nfmt.Println(\"Key d:\", d)\n```\n\nYes, you guessed it! we will get the zero value of the map's value type.\n\n```bash\n$ go run main.go\nKey c: {Steve}\nKey d: {}\n```\n\n## Exists\n\nWhen you retrieve the value assigned to a given key, it returns an additional boolean value as well. The boolean variable will be `true` if the key exists, and `false` otherwise.\n\nLet's try this in an example:\n\n```go\n...\nc, ok := m[\"c\"]\nfmt.Println(\"Key c:\", c, ok)\n\nd, ok := m[\"d\"]\nfmt.Println(\"Key d:\", d, ok)\n```\n\n```bash\n$ go run main.go\nKey c: {Steve} Present: true\nKey d: {} Present: false\n```\n\n## Update\n\nWe can also update the value for a key by simply re-assigning a key.\n\n```go\n...\nm[\"a\"] = \"Roger\"\n```\n\n```bash\n$ go run main.go\nmap[a:{Roger} b:{Seth} c:{Steve}]\n```\n\n## Delete\n\nOr, we can delete the key using the built-in `delete` function.\n\nHere's how the syntax looks:\n\n```go\n...\ndelete(m, \"a\")\n```\n\nThe first argument is the map, and the second is the key we want to delete.\n\nThe `delete()` function doesn't return any value. Also, it doesn't do anything if the key doesn't exist in the map.\n\n```bash\n$ go run main.go\nmap[a:{Roger} c:{Steve}]\n```\n\n## Iteration\n\nSimilar to arrays or slices, we can iterate over maps with the `range` keyword.\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tvar m = map[string]User{\n\t\t\"a\": {\"Peter\"},\n\t\t\"b\": {\"Seth\"},\n\t}\n\n\tm[\"c\"] = User{\"Steve\"}\n\n\tfor key, value := range m {\n\t\tfmt.Println(\"Key: %s, Value: %v\", key, value)\n\t}\n}\n```\n\n```bash\n$ go run main.go\nKey: c, Value: {Steve}\nKey: a, Value: {Peter}\nKey: b, Value: {Seth}\n```\n\nNote that a map is an unordered collection, and therefore the iteration order of a map is not guaranteed to be the same every time we iterate over it.\n\n## Properties\n\nLastly, let's talk about map properties.\n\nMaps are reference types, which means when we assign a map to a new variable, they both refer to the same underlying data structure.\n\nTherefore, changes done by one variable will be visible to the other.\n\n```go\npackage main\n\nimport \"fmt\"\n\ntype User struct {\n\tName string\n}\n\nfunc main() {\n\tvar m1 = map[string]User{\n\t\t\"a\": {\"Peter\"},\n\t\t\"b\": {\"Seth\"},\n\t}\n\n\tm2 := m1\n\tm2[\"c\"] = User{\"Steve\"}\n\n\tfmt.Println(m1) // Output: map[a:{Peter} b:{Seth} c:{Steve}]\n\tfmt.Println(m2) // Output: map[a:{Peter} b:{Seth} c:{Steve}]\n}\n```\n\n# Interfaces\n\nIn this section, let's talk about the interfaces.\n\n## What is an interface?\n\nSo, an interface in Go is an **abstract type** that is defined using a set of method signatures. The interface defines the **behavior** for similar types of objects.\n\n_Here, **behavior** is a key term that we will discuss shortly._\n\nLet's take a look at an example to understand this better.\n\nOne of the best real-world examples of interfaces is the power socket. Imagine that we need to connect different devices to the power socket.\n\n![no-interface](https://raw.githubusercontent.com/karanpratapsingh/portfolio/master/public/static/courses/go/chapter-III/interfaces/no-interface.png)\n\nLet's try to implement this. Here are the device types we will be using.\n\n```go\ntype mobile struct {\n\tbrand string\n}\n\ntype laptop struct {\n\tcpu string\n}\n\ntype toaster struct {\n\tamount int\n}\n\ntype kettle struct {\n\tquantity string\n}\n\ntype socket struct{}\n```\n\nNow, let's define a `Draw` method on a type, let's say `mobile`. Here we will simply print the properties of the type.\n\n```go\nfunc (m mobile) Draw(power int) {\n\tfmt.Printf(\"%T -\u003e brand: %s, power: %d\", m, m.brand, power)\n}\n```\n\nGreat, now we will define the `Plug` method on the `socket` type which accepts our `mobile` type as an argument.\n\n```go\nfunc (socket) Plug(device mobile, power int) {\n\tdevice.Draw(power)\n}\n```\n\nLet's try to _\"connect\"_ or _\"plug in\"_ the `mobile` type to our `socket` type in the `main` function.\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tm := mobile{\"Apple\"}\n\n\ts := socket{}\n\ts.Plug(m, 10)\n}\n```\n\nAnd if we run this we'll see the following.\n\n```bash\n$ go run main.go\nmain.mobile -\u003e brand: Apple, power: 10\n```\n\nThis is interesting, but let's say now we want to connect our `laptop` type.\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tm := mobile{\"Apple\"}\n\tl := laptop{\"Intel i9\"}\n\n\ts := socket{}\n\n\ts.Plug(m, 10)\n\ts.Plug(l, 50) // Error: cannot use l as mobile value in argument\n}\n```\n\nAs we can see, this will throw an error.\n\n**What should we do now? Define another method? Such as `PlugLaptop`?**\n\nSure, but then every time we add a new device type we will need to add a new method to the socket type as well and that's not ideal.\n\nThis is where the `interface` comes in. Essentially, we want to define a **contract** that, in the future, must be implemented.\n\nWe can simply define an interface such as `PowerDrawer` and use it in our `Plug` function to allow any device that satisfies the criteria, which is that the type must have a `Draw` method matching the signature that the interface requires.\n\nAnd anyways, the socket doesn't need to know anything about our device and can simply call the `Draw` method.\n\n![interface](https://raw.githubusercontent.com/karanpratapsingh/portfolio/master/public/static/courses/go/chapter-III/interfaces/interface.png)\n\nNow let's try to implement our `PowerDrawer` interface. Here's how it will look.\n\nThe convention is to use **\"-er\"** as a suffix in the name. And as we discussed earlier, an interface should only describe the **expected behavior**. Which in our case is the `Draw` method.\n\n![interface-implementation](https://raw.githubusercontent.com/karanpratapsingh/portfolio/master/public/static/courses/go/chapter-III/interfaces/interface-implementation.png)\n\n```go\ntype PowerDrawer interface {\n\tDraw(power int)\n}\n```\n\nNow, we need to update our `Plug` method to accept a device that implements the `PowerDrawer` interface as an argument.\n\n```go\nfunc (socket) Plug(device PowerDrawer, power int) {\n\tdevice.Draw(power)\n}\n```\n\nAnd to satisfy the interface, we can simply add `Draw` methods to all the device types.\n\n```go\ntype mobile struct {\n\tbrand string\n}\n\nfunc (m mobile) Draw(power int) {\n\tfmt.Printf(\"%T -\u003e brand: %s, power: %d\\n\", m, m.brand, power)\n}\n\ntype laptop struct {\n\tcpu string\n}\n\nfunc (l laptop) Draw(power int) {\n\tfmt.Printf(\"%T -\u003e cpu: %s, power: %d\\n\", l, l.cpu, power)\n}\n\ntype toaster struct {\n\tamount int\n}\n\nfunc (t toaster) Draw(power int) {\n\tfmt.Printf(\"%T -\u003e amount: %d, power: %d\\n\", t, t.amount, power)\n}\n\ntype kettle struct {\n\tquantity string\n}\n\nfunc (k kettle) Draw(power int) {\n\tfmt.Printf(\"%T -\u003e quantity: %s, power: %d\\n\", k, k.quantity, power)\n}\n```\n\nNow, we can connect all our devices to the socket with the help of our interface!\n\n```go\nfunc main() {\n\tm := mobile{\"Apple\"}\n\tl := laptop{\"Intel i9\"}\n\tt := toaster{4}\n\tk := kettle{\"50%\"}\n\n\ts := socket{}\n\n\ts.Plug(m, 10)\n\ts.Plug(l, 50)\n\ts.Plug(t, 30)\n\ts.Plug(k, 25)\n}\n```\n\nAnd it works just as we expected.\n\n```bash\n$ go run main.go\nmain.mobile -\u003e brand: Apple, power: 10\nmain.laptop -\u003e cpu: Intel i9, power: 50\nmain.toaster -\u003e amount: 4, power: 30\nmain.kettle -\u003e quantity: Half Empty, power: 25\n```\n\n**But why is this considered such a powerful concept?**\n\nWell, an interface can help us decouple our types. For example, because we have the interface, we don't need to update our `socket` implementation. We can just define a new device type with a `Draw` method.\n\nUnlike other languages, Go Interfaces are implemented **implicitly**, so we don't need something like an `implements` keyword. This means that a type satisfies an interface automatically when it has _\"all the methods\"_ of the interface.\n\n## Empty Interface\n\nNext, let's talk about the empty interface. An empty interface can take on a value of any type.\n\nHere's how we declare it.\n\n```go\nvar x interface{}\n```\n\n**But why do we need it?**\n\nEmpty interfaces can be used to handle values of unknown types.\n\nSome examples are:\n\n- Reading heterogeneous data from an API.\n- Variables of an unknown type, like in the `fmt.Println` function.\n\nTo use a value of type empty `interface{}`, we can use _type assertion_ or a _type switch_ to determine the type of the value.\n\n## Type Assertion\n\nA _type assertion_ provides access to an interface value's underlying concrete value.\n\nFor example:\n\n```go\nfunc main() {\n\tvar i interface{} = \"hello\"\n\n\ts := i.(string)\n\tfmt.Println(s)\n}\n```\n\nThis statement asserts that the interface value holds a concrete type and assigns the underlying type value to the variable.\n\nWe can also test whether an interface value holds a specific type.\n\nA type assertion can return two values:\n\n- The first one is the underlying value.\n- The second is a boolean value that reports whether the assertion succeeded.\n\n```go\ns, ok := i.(string)\nfmt.Println(s, ok)\n```\n\nThis can help us test whether an interface value holds a specific type or not.\n\nIn a way, this is similar to how we read values from a map.\n\nAnd If this is not the case then, `ok` will be false and the value will be the zero value of the type, and no panic will occur.\n\n```go\nf, ok := i.(float64)\nfmt.Println(f, ok)\n```\n\nBut if the interface does not hold the type, the statement will trigger a panic.\n\n```go\nf = i.(float64)\nfmt.Println(f) // Panic!\n```\n\n```bash\n$ go run main.go\nhello\nhello true\n0 false\npanic: interface conversion: interface {} is string, not float64\n```\n\n## Type Switch\n\nHere, a `switch` statement can be used to determine the type of a variable of type empty `interface{}`.\n\n```go\nvar t interface{}\nt = \"hello\"\n\nswitch t := t.(type) {\ncase string:\n\tfmt.Printf(\"string: %s\\n\", t)\ncase bool:\n\tfmt.Printf(\"boolean: %v\\n\", t)\ncase int:\n\tfmt.Printf(\"integer: %d\\n\", t)\ndefault:\n\tfmt.Printf(\"unexpected: %T\\n\", t)\n}\n```\n\nAnd if we run this, we can verify that we have a `string` type.\n\n```bash\n$ go run main.go\nstring: hello\n```\n\n## Properties\n\nLet's discuss some properties of interfaces.\n\n### Zero value\n\nThe zero value of an interface is `nil`.\n\n```go\npackage main\n\nimport \"fmt\"\n\ntype MyInterface interface {\n\tMethod()\n}\n\nfunc main() {\n\tvar i MyInterface\n\n\tfmt.Println(i) // Output: \u003cnil\u003e\n}\n```\n\n### Embedding\n\nWe can embed interfaces like structs. For example:\n\n```go\ntype interface1 interface {\n    Method1()\n}\n\ntype interface2 interface {\n    Method2()\n}\n\ntype interface3 interface {\n    interface1\n    interface2\n}\n```\n\n### Values\n\nInterface values are comparable.\n\n```go\npackage main\n\nimport \"fmt\"\n\ntype MyInterface interface {\n\tMethod()\n}\n\ntype MyType struct{}\n\nfunc (MyType) Method() {}\n\nfunc main() {\n\tt := MyType{}\n\tvar i MyInterface = MyType{}\n\n\tfmt.Println(t == i)\n}\n```\n\n### Interface Values\n\nUnder the hood, an interface value can be thought of as a tuple consisting of a value and a concrete type.\n\n```go\npackage main\n\nimport \"fmt\"\n\ntype MyInterface interface {\n\tMethod()\n}\n\ntype MyType struct {\n\tproperty int\n}\n\nfunc (MyType) Method() {}\n\nfunc main() {\n\tvar i MyInterface\n\n\ti = MyType{10}\n\n\tfmt.Printf(\"(%v, %T)\\n\", i, i) // Output: ({10}, main.MyType)\n}\n```\n\nWith that, we covered interfaces in Go.\n\nIt's a really powerful feature, but remember, _\"Bigger the interface, the weaker the abstraction\"_ - Rob Pike.\n\n# Errors\n\nIn this tutorial, let's talk about error handling.\n\nNotice how I said errors and not exceptions as there is no exception handling in Go.\n\nInstead, we can just return a built-in `error` type which is an interface type.\n\n```go\ntype error interface {\n    Error() string\n}\n```\n\nWe will circle back to this shortly. First, let's try to understand the basics.\n\nSo, let's declare a simple `Divide` function which, as the name suggests, will divide integer `a` by `b`.\n\n```go\nfunc Divide(a, b int) int {\n\treturn a/b\n}\n```\n\nGreat. Now, we want to return an error, let's say, to prevent the division by zero. This brings us to error construction.\n\n## Constructing Errors\n\nThere are multiple ways to do this, but we will look at the two most common ones.\n\n### `errors` package\n\nThe first is by using the `New` function provided by the `errors` package.\n\n```go\npackage main\n\nimport \"errors\"\n\nfunc main() {}\n\nfunc Divide(a, b int) (int, error) {\n\tif b == 0 {\n\t\treturn 0, errors.New(\"cannot divide by zero\")\n\t}\n\n\treturn a/b, nil\n}\n```\n\nNotice, how we return an `error` with the result. And if there is no error we simply return `nil` as it is the zero value of an error because after all, it's an interface.\n\nBut how do we handle it? So, for that, let's call the `Divide` function in our `main` function.\n\n```go\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\nfunc main() {\n\tresult, err := Divide(4, 0)\n\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\t// Do something with the error\n\t\treturn\n\t}\n\n\tfmt.Println(result)\n\t// Use the result\n}\n\nfunc Divide(a, b int) (int, error) {...}\n```\n\n```bash\n$ go run main.go\ncannot divide by zero\n```\n\nAs you can see, we simply check if the error is `nil` and build our logic accordingly. This is considered quite idiomatic in Go and you will see this being used a lot.\n\nAnother way to construct our errors is by using the `fmt.Errorf` function.\n\nThis function is similar to `fmt.Sprintf` and it lets us format our error. But instead of returning a string, it returns an error.\n\nIt is often used to add some context or detail to our errors.\n\n```go\n...\nfunc Divide(a, b int) (int, error) {\n\tif b == 0 {\n\t\treturn 0, fmt.Errorf(\"cannot divide %d by zero\", a)\n\t}\n\n\treturn a/b, nil\n}\n```\n\nAnd it should work similarly.\n\n```bash\n$ go run main.go\ncannot divide 4 by zero\n```\n\n### Sentinel Errors\n\nAnother important technique in Go is defining expected Errors so they can be checked explicitly in other parts of the code. These are sometimes referred to as sentinel errors.\n\n```go\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\nvar ErrDivideByZero = errors.New(\"cannot divide by zero\")\n\nfunc main() {...}\n\nfunc Divide(a, b int) (int, error) {\n\tif b == 0 {\n\t\treturn 0, ErrDivideByZero\n\t}\n\n\treturn a/b, nil\n}\n```\n\nIn Go, it is considered conventional to prefix the variable with `Err`. For example, `ErrNotFound`.\n\n**But what's the point?**\n\nSo, this becomes useful when we need to execute a different branch of code if a certain kind of error is encountered.\n\nFor example, now we can check explicitly which error occurred using the `errors.Is` function.\n\n```go\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\nfunc main() {\n\tresult, err := Divide(4, 0)\n\n\tif err != nil {\n\t\tswitch {\n    case errors.Is(err, ErrDivideByZero):\n        fmt.Println(err)\n\t\t\t\t// Do something with the error\n    default:\n        fmt.Println(\"no idea!\")\n    }\n\n\t\treturn\n\t}\n\n\tfmt.Println(result)\n\t// Use the result\n}\n\nfunc Divide(a, b int) (int, error) {...}\n```\n\n```bash\n$ go run main.go\ncannot divide by zero\n```\n\n## Custom Errors\n\nThis strategy covers most of the error handling use cases. But sometimes we need additional functionalities such as dynamic values inside of our errors.\n\nEarlier, we saw that `error` is just an interface. So basically, anything can be an `error` as long as it implements the `Error()` method which returns an error message as a string.\n\nSo, let's define our custom `DivisionError` struct which will contain an error code and a message.\n\n```go\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\ntype DivisionError struct {\n\tCode int\n\tMsg  string\n}\n\nfunc (d DivisionError) Error() string {\n\treturn fmt.Sprintf(\"code %d: %s\", d.Code, d.Msg)\n}\n\nfunc main() {...}\n\nfunc Divide(a, b int) (int, error) {\n\tif b == 0 {\n\t\treturn 0, DivisionError{\n\t\t\tCode: 2000,\n\t\t\tMsg:  \"cannot divide by zero\",\n\t\t}\n\t}\n\n\treturn a/b, nil\n}\n```\n\nHere, we will use `errors.As` instead of `errors.Is` function to convert the error to the correct type.\n\n```go\nfunc main() {\n\tresult, err := Divide(4, 0)\n\n\tif err != nil {\n\t\tvar divErr DivisionError\n\n\t\tswitch {\n\t\tcase errors.As(err, \u0026divErr):\n\t\t\tfmt.Println(divErr)\n\t\t\t// Do something with the error\n\t\tdefault:\n\t\t\tfmt.Println(\"no idea!\")\n\t\t}\n\n\t\treturn\n\t}\n\n\tfmt.Println(result)\n\t// Use the result\n}\n\nfunc Divide(a, b int) (int, error) {...}\n```\n\n```bash\n$ go run main.go\ncode 2000: cannot divide by zero\n```\n\n**But what's the difference between `errors.Is` and `errors.As`?**\n\nThe difference is that this function checks whether the error has a specific type, unlike the [`Is`](https://pkg.go.dev/errors#Is) function, which examines if it is a particular error object.\n\nWe can also use type assertions but it's not preferred.\n\n```go\nfunc main() {\n\tresult, err := Divide(4, 0)\n\n\tif e, ok := err.(DivisionError); ok {\n\t\tfmt.Println(e.Code, e.Msg) // Output: 2000 cannot divide by zero\n\t\treturn\n\t}\n\n\tfmt.Println(result)\n}\n```\n\nLastly, I will say that error handling in Go is quite different compared to the traditional `try/catch` idiom in other languages. But it is very powerful as it encourages the developer to actually handle the error in an explicit way, which improves readability as well.\n\n# Panic and Recover\n\nSo earlier, we learned that the idiomatic way of handling abnormal conditions in a Go program is using errors. While errors are sufficient for most cases, there are some situations where the program cannot continue.\n\nIn those cases, we can use the built-in `panic` function.\n\n## Panic\n\n```go\nfunc panic(interface{})\n```\n\nThe panic is a built-in function that stops the normal execution of the current `goroutine`. When a function calls `panic`, the normal execution of the function stops immediately and the control is returned to the caller. This is repeated until the program exits with the panic message and stack trace.\n\n_Note: We will discuss `goroutines` later in the course._\n\nSo, let's see how we can use the `panic` function.\n\n```go\npackage main\n\nfunc main() {\n\tWillPanic()\n}\n\nfunc WillPanic() {\n\tpanic(\"Woah\")\n}\n```\n\nAnd if we run this, we can see `panic` in action.\n\n```bash\n$ go run main.go\npanic: Woah\n\ngoroutine 1 [running]:\nmain.WillPanic(...)\n        .../main.go:8\nmain.main()\n        .../main.go:4 +0x38\nexit status 2\n```\n\nAs expected, our program printed the panic message, followed by the stack trace, and then it was terminated.\n\nSo, the question is, what to do when an unexpected panic happens?\n\n## Recover\n\nWell, it is possible to regain control of a panicking program using the built-in `recover` function, along with the `defer` keyword.\n\n```go\nfunc recover() interface{}\n```\n\nLet's try an example by creating a `handlePanic` function. And then, we can call it using `defer`.\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tWillPanic()\n}\n\nfunc handlePanic() {\n\tdata := recover()\n\tfmt.Println(\"Recovered:\", data)\n}\n\nfunc WillPanic() {\n\tdefer handlePanic()\n\n\tpanic(\"Woah\")\n}\n```\n\n```bash\n$ go run main.go\nRecovered: Woah\n```\n\nAs we can see, our panic was recovered and now our program can continue execution.\n\nLastly, I will mention that `panic` and `recover` can be considered similar to the `try/catch` idiom in other languages. But one important factor is that we should avoid panic and recover and use [errors](https://karanpratapsingh.com/courses/go/errors) when possible.\n\nIf so, then this brings us to the question, when should we use `panic`?\n\n## Use Cases\n\nThere are two valid use cases for `panic`:\n\n- **An unrecoverable error**\n\nWhich can be a situation where the program cannot simply continue its execution.\n\nFor example, reading a configuration file which is important to start the program, as there is nothing else to do if the file read itself fails.\n\n- **Developer error**\n\nThis is the most common situation. For example, dereferencing a pointer when the value is `nil` will cause a panic.\n\n# Testing\n\nIn this tutorial, we will talk about testing in Go. So, let's start using a simple example.\n\nWe have created a `math` package that contains an `Add` function Which as the name suggests, adds two integers.\n\n```go\npackage math\n\nfunc Add(a, b int) int {\n\treturn a + b\n}\n```\n\nIt's being used in our `main` package like this.\n\n```go\npackage main\n\nimport (\n\t\"example/math\"\n\t\"fmt\"\n)\n\nfunc main() {\n\tresult := math.Add(2, 2)\n\tfmt.Println(result)\n}\n\n```\n\nAnd, if we run this, we should see the result.\n\n```bash\n$ go run main.go\n4\n```\n\nNow, we want to test our `Add` function. So, in Go, we declare test files with `_test` suffix in the file name. So for our `add.go`, we will create a test as `add_test.go`. Our project structure should look like this.\n\n```bash\n.\n├── go.mod\n├── main.go\n└── math\n    ├── add.go\n    └── add_test.go\n```\n\nWe will start by using a `math_test` package, and importing the `testing` package from the standard library. That's right! Testing is built into Go, unlike many other languages.\n\nBut wait...why do we need to use `math_test` as our package, can't we just use the same `math` package?\n\nWell yes, we can write our test in the same package if we wanted, but I personally think doing this in a separate package helps us write tests in a more decoupled way.\n\nNow, we can create our `TestAdd` function. It will take an argument of type `testing.T` which will provide us with helpful methods.\n\n```go\npackage math_test\n\nimport \"testing\"\n\nfunc TestAdd(t *testing.T) {}\n```\n\nBefore we add any testing logic, let's try to run it. But this time, we cannot use `go run` command, instead, we will use the `go test` command.\n\n```bash\n$ go test ./math\nok      example/math 0.429s\n```\n\nHere, we will have our package name which is `math`, but we can also use the relative path `./...` to test all packages.\n\n```bash\n$ go test ./...\n?       example [no test files]\nok      example/math 0.348s\n```\n\nAnd if Go doesn't find any test in a package, it will let us know.\n\nPerfect, let's write some test code. To do this, we will check our result with an expected value and if they do not match, we can use the `t.Fail` method to fail the test.\n\n```go\npackage math_test\n\nimport \"testing\"\n\nfunc TestAdd(t *testing.T) {\n\tgot := math.Add(1, 1)\n\texpected := 2\n\n\tif got != expected {\n\t\tt.Fail()\n\t}\n}\n```\n\nGreat! Our test seems to have passed.\n\n```bash\n$ go test math\nok      example/math    0.412s\n```\n\nLet's also see what happens if we fail the test, for that, we can simply change our expected result.\n\n```go\npackage math_test\n\nimport \"testing\"\n\nfunc TestAdd(t *testing.T) {\n\tgot := math.Add(1, 1)\n\texpected := 3\n\n\tif got != expected {\n\t\tt.Fail()\n\t}\n}\n```\n\n```bash\n$ go test ./math\nok      example/math    (cached)\n```\n\nIf you see this, don't worry. For optimization, our tests are cached. We can use the `go clean` command to clear our cache and then re-run the test.\n\n```bash\n$ go clean -testcache\n$ go test ./math\n--- FAIL: TestAdd (0.00s)\nFAIL\nFAIL    example/math    0.354s\nFAIL\n```\n\nSo, this is what a test failure will look like.\n\n## Table driven tests\n\nThis brings us to table-driven tests. But what exactly are they?\n\nSo earlier, we had function arguments and expected variables which we compared to determine if our tests passed or fail. But what if we defined all that in a slice and iterate over that? This will make our tests a little bit more flexible and help us run multiple cases easily.\n\nDon't worry, we will learn this by example. So we will start by defining our `addTestCase` struct.\n\n```go\npackage math_test\n\nimport (\n\t\"example/math\"\n\t\"testing\"\n)\n\ntype addTestCase struct {\n\ta, b, expected int\n}\n\nvar testCases = []addTestCase{\n\t{1, 1, 3},\n\t{25, 25, 50},\n\t{2, 1, 3},\n\t{1, 10, 11},\n}\n\nfunc TestAdd(t *testing.T) {\n\n\tfor _, tc := range testCases {\n\t\tgot := math.Add(tc.a, tc.b)\n\n\t\tif got != tc.expected {\n\t\t\tt.Errorf(\"Expected %d but got %d\", tc.expected, got)\n\t\t}\n\t}\n}\n```\n\nNotice, how we declared `addTestCase` with a lower case. That's right we don't want to export it as it's not useful outside our testing logic. Let's run our test.\n\n```bash\n$ go run main.go\n--- FAIL: TestAdd (0.00s)\n    add_test.go:25: Expected 3 but got 2\nFAIL\nFAIL    example/math    0.334s\nFAIL\n```\n\nSeems like our tests broke, let's fix them by updating our test cases.\n\n```go\nvar testCases = []addTestCase{\n\t{1, 1, 2},\n\t{25, 25, 50},\n\t{2, 1, 3},\n\t{1, 10, 11},\n}\n```\n\nPerfect, it's working!\n\n```bash\n$ go run main.go\nok      example/math    0.589s\n```\n\n## Code coverage\n\nFinally, let's talk about code coverage. When writing tests, it is often important to know how much of your actual code the tests cover. This is generally referred to as code coverage.\n\nTo calculate and export the coverage for our test, we can simply use the `-coverprofile` argument with the `go test` command.\n\n```bash\n$ go test ./math -coverprofile=coverage.out\nok      example/math    0.385s  coverage: 100.0% of statements\n```\n\nSeems like we have great coverage. Let's also check the report using the `go tool cover` command which gives us a detailed report.\n\n```bash\n$ go tool cover -html=coverage.out\n```\n\n![coverage](https://raw.githubusercontent.com/karanpratapsingh/portfolio/master/public/static/courses/go/chapter-III/testing/coverage.png)\n\nAs we can see, this is a much more readable format. And best of all, it is built right into standard tooling.\n\n## Fuzz testing\n\nLastly, let's look at fuzz testing which was introduced in Go version 1.18.\n\nFuzzing is a type of automated testing that continuously manipulates inputs to a program to find bugs.\n\nGo fuzzing uses coverage guidance to intelligently walk through the code being fuzzed to find and report failures to the user.\n\nSince it can reach edge cases that humans often miss, fuzz testing can be particularly valuable for finding bugs and security exploits.\n\nLet's try an example:\n\n```go\nfunc FuzzTestAdd(f *testing.F) {\n\tf.Fuzz(func(t *testing.T, a, b int) {\n\t\tmath.Add(a , b)\n\t})\n}\n```\n\nIf we run this, we'll see that it'll automatically create test cases. Because our `Add` function is quite simple, tests will pass.\n\n```bash\n$ go test -fuzz FuzzTestAdd example/math\nfuzz: elapsed: 0s, gathering baseline coverage: 0/192 completed\nfuzz: elapsed: 0s, gathering baseline coverage: 192/192 completed, now fuzzing with 8 workers\nfuzz: elapsed: 3s, execs: 325017 (108336/sec), new interesting: 11 (total: 202)\nfuzz: elapsed: 6s, execs: 680218 (118402/sec), new interesting: 12 (total: 203)\nfuzz: elapsed: 9s, execs: 1039901 (119895/sec), new interesting: 19 (total: 210)\nfuzz: elapsed: 12s, execs: 1386684 (115594/sec), new interesting: 21 (total: 212)\nPASS\nok      foo 12.692s\n```\n\nBut if we update our `Add` function with a random edge case such that the program will panic if `b + 10` is greater than `a`.\n\n```go\nfunc Add(a, b int) int {\n\tif a \u003e b + 10 {\n\t\tpanic(\"B must be greater than A\")\n\t}\n\n\treturn a + b\n}\n```\n\nAnd if we re-run the test, this edge case will be caught by fuzz testing.\n\n```bash\n$ go test -fuzz FuzzTestAdd example/math\nwarning: starting with empty corpus\nfuzz: elapsed: 0s, execs: 0 (0/sec), new interesting: 0 (total: 0)\nfuzz: elapsed: 0s, execs: 1 (25/sec), new interesting: 0 (total: 0)\n--- FAIL: FuzzTestAdd (0.04s)\n    --- FAIL: FuzzTestAdd (0.00s)\n        testing.go:1349: panic: B is greater than A\n```\n\nI think this is a really cool feature of Go 1.18. You can learn more about fuzz testing from the [official Go blog](https://go.dev/doc/fuzz).\n\n# Generics\n\nIn this section, we will learn about Generics which is a much awaited feature that was released with Go version 1.18.\n\n## What are Generics?\n\nGenerics means parameterized types. Put simply, generics allow programmers to write code where the type can be specified later because the type isn't immediately relevant.\n\nLet's take a look at an example to understand this better.\n\nFor our example, we have simple sum functions for different types such as `int`, `float64`, and `string`. Since method overriding is not allowed in Go we usually have to create new functions.\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc sumInt(a, b int) int {\n\treturn a + b\n}\n\nfunc sumFloat(a, b float64) float64 {\n\treturn a + b\n}\n\nfunc sumString(a, b string) string {\n\treturn a + b\n}\n\nfunc main() {\n\tfmt.Println(sumInt(1, 2))\n\tfmt.Println(sumFloat(4.0, 2.0))\n\tfmt.Println(sumString(\"a\", \"b\"))\n}\n```\n\nAs we can see, apart from the types, these functions are pretty similar.\n\nLet's see how we can define a generic function.\n\n```go\nfunc fnName[T constraint]() {\n\t...\n}\n```\n\nHere, `T` is our type parameter and `constraint` will be the interface that allows any type implementing the interface.\n\nI know, I know, this is confusing. So, let's start building our generic `sum` function.\n\nHere, we will use `T` as our type parameter with an empty `interface{}` as our constraint.\n\n```go\nfunc sum[T interface{}](a, b T) T {\n\tfmt.Println(a, b)\n}\n```\n\nAlso, starting with Go 1.18 we can use `any`, which is pretty much equivalent to the empty interface.\n\n```go\nfunc sum[T any](a, b T) T {\n\tfmt.Println(a, b)\n}\n```\n\nWith type parameters, comes the need to pass type arguments, which can make our code verbose.\n\n```go\nsum[int](1, 2) // explicit type argument\nsum[float64](4.0, 2.0)\nsum[string](\"a\", \"b\")\n```\n\nLuckily, Go 1.18 comes with **type inference** which helps us to write code that calls generic functions without explicit types.\n\n```go\nsum(1, 2)\nsum(4.0, 2.0)\nsum(\"a\", \"b\")\n```\n\nLet's run this and see if it works.\n\n```bash\n$ go run main.go\n1 2\n4 2\na b\n```\n\nNow, let's update the `sum` function to add our variables.\n\n```go\nfunc sum[T any](a, b T) T {\n\treturn a + b\n}\n```\n\n```go\nfmt.Println(sum(1, 2))\nfmt.Println(sum(4.0, 2.0))\nfmt.Println(sum(\"a\", \"b\"))\n```\n\nBut now if we run this, we will get an error that operator `+` is not defined in the constraint.\n\n```bash\n$ go run main.go\n./main.go:6:9: invalid operation: operator + not defined on a (variable of type T constrained by any)\n```\n\nWhile constraint of type `any` generally works it does not support operators.\n\nSo let's define our own custom constraint using an interface. Our interface should define a type set containing `int`, `float`, and `string`.\n\n![typeset](https://raw.githubusercontent.com/karanpratapsingh/portfolio/master/public/static/courses/go/chapter-III/generics/typeset.png)\n\nHere's how our `SumConstraint` interface looks.\n\n```go\ntype SumConstraint interface {\n\tint | float64 | string\n}\n\nfunc sum[T SumConstraint](a, b T) T {\n\treturn a + b\n}\n\nfunc main() {\n\tfmt.Println(sum(1, 2))\n\tfmt.Println(sum(4.0, 2.0))\n\tfmt.Println(sum(\"a\", \"b\"))\n}\n```\n\nAnd this should work as expected.\n\n```bash\n$ go run main.go\n3\n6\nab\n```\n\nWe can also use the `constraints` package which defines a set of useful constraints to be used with type parameters.\n\n```go\ntype Signed interface {\n\t~int | ~int8 | ~int16 | ~int32 | ~int64\n}\n\ntype Unsigned interface {\n\t~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr\n}\n\ntype Integer interface {\n\tSigned | Unsigned\n}\n\ntype Float interface {\n\t~float32 | ~float64\n}\n\ntype Complex interface {\n\t~complex64 | ~complex128\n}\n\ntype Ordered interface {\n\tInteger | Float | ~string\n}\n```\n\nFor that, we will need to install the `constraints` package.\n\n```bash\n$ go get golang.org/x/exp/constraints\ngo: added golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd\n```\n\n```go\nimport (\n\t\"fmt\"\n\n\t\"golang.org/x/exp/constraints\"\n)\n\nfunc sum[T constraints.Ordered](a, b T) T {\n\treturn a + b\n}\n\nfunc main() {\n\tfmt.Println(sum(1, 2))\n\tfmt.Println(sum(4.0, 2.0))\n\tfmt.Println(sum(\"a\", \"b\"))\n}\n```\n\nHere we are using the `Ordered` constraint.\n\n```go\ntype Ordered interface {\n\tInteger | Float | ~string\n}\n```\n\n`~` is a new token added to Go and the expression `~string` means the set of all types whose underlying type is `string`.\n\nAnd it still works as expected.\n\n```bash\n$ go run main.go\n3\n6\nab\n```\n\nGenerics is an amazing feature because it permits writing abstract functions that can drastically reduce code duplication in certain cases.\n\n## When to use generics\n\nSo, when to use generics? We can take the following use cases as an example:\n\n- Functions that operate on arrays, slices, maps, and channels.\n- General purpose data structures like stack or linked list.\n- To reduce code duplication.\n\nLastly, I will add that while generics are a great addition to the language, they should be used sparingly.\n\nAnd, it is advised to start simple and only write generic code once we have written very similar code at least 2 or 3 times.\n\n# Concurrency\n\nIn this lesson, we will learn about concurrency which is one of the most powerful features of Go.\n\nSo, let's start by asking What is _\"concurrency\"_?\n\n## What is Concurrency\n\nConcurrency, by definition, is the ability to break down a computer program or algorithm into individual parts, which can be executed independently.\n\nThe final outcome of a concurrent program is the same as that of a program that has been executed sequentially.\n\nUsing concurrency, we can achieve the same results in lesser time, thus increasing the overall performance and efficiency of our programs.\n\n## Concurrency vs Parallelism\n\n![concurrency-vs-parallelism](https://raw.githubusercontent.com/karanpratapsingh/portfolio/master/public/static/courses/go/chapter-IV/concurrency/concurrency-vs-parallelism.png)\n\nA lot of people confuse concurrency with parallelism because they both somewhat imply executing code","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkaranpratapsingh%2Flearn-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkaranpratapsingh%2Flearn-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkaranpratapsingh%2Flearn-go/lists"}