{"id":20196527,"url":"https://github.com/endalk200/go-docs","last_synced_at":"2025-08-08T21:09:13.866Z","repository":{"id":161759261,"uuid":"636303059","full_name":"endalk200/go-docs","owner":"endalk200","description":"Learn go through small docs, code snippets with docs, exercise and mini projects.","archived":false,"fork":false,"pushed_at":"2023-05-07T19:11:05.000Z","size":98,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-26T17:01:56.719Z","etag":null,"topics":["go","golang","language","learn-go","learning-by-doing"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/endalk200.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-05-04T14:42:25.000Z","updated_at":"2024-08-24T15:45:11.000Z","dependencies_parsed_at":"2024-06-21T15:42:41.503Z","dependency_job_id":"99ca152f-ee4b-4eb3-89fc-d440ce45dfcc","html_url":"https://github.com/endalk200/go-docs","commit_stats":null,"previous_names":["endalk200/go-docs","endalk200/learn-go"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endalk200%2Fgo-docs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endalk200%2Fgo-docs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endalk200%2Fgo-docs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endalk200%2Fgo-docs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/endalk200","download_url":"https://codeload.github.com/endalk200/go-docs/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241629769,"owners_count":19993710,"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":["go","golang","language","learn-go","learning-by-doing"],"created_at":"2024-11-14T04:24:35.542Z","updated_at":"2025-03-03T08:15:02.095Z","avatar_url":"https://github.com/endalk200.png","language":"Go","readme":"\u003e Learn go through concept deep dive, code snippets with comments, excercises and mini projects\n\n# Learn Go\n\n# Table of contents\n\n- [Learn Go](#learn-go)\n  - [GoLang History](#golang-history)\n  - [Why GoLang?](#why-golang-)\n  - [Advantages of GoLang](#advantages-of-golang)\n  - [Components of the Golang](#components-of-the-golang)\n    - [Compiler](#compiler)\n    - [Standard Library](#standard-library)\n    - [Runtime](#runtime)\n    - [Tools](#tools)\n    - [Third-party packages](#third-party-packages)\n  - [Go compiler deep dive](#go-compiler-deep-dive)\n    - [Phase 1 - Lexing, Parsing and AST generation](#phase-1---lexing--parsing-and-ast-generation)\n    - [Phase 2 - Type checking](#phase-2---type-checking)\n    - [Phase 3 - SSA generation](#phase-3---ssa-generation)\n    - [Phase 4 - Machine code generation](#phase-4---machine-code-generation)\n  - [Continue learning](#continue-learning)\n  - [Syntax Basics](/docs/data-types.md#data-types-in-go)\n    - [Arrays](/docs/data-types.md#arrays)\n    - [Slices](/docs/data-types.md#slices)\n\nGoogle's GoLang, shortened as Go is an open-source programming language that was created in 2009. It is intended for efficient, concurrent, and scalable system programming with an emphasis on simplicity and usability. Go is a popular choice for building networked and distributed systems, web applications, and other types of software because it has strong typing, garbage collection, and syntax similar to C.\n\n## GoLang History\n\nGoogle first unveiled Go programming language in 2009. It was introduced as a language that could address some of the challenges associated with large-scale distributed systems while remaining easy to use and efficiently driving the development of Go.\n\nThe language was developed by three Google engineers: Robert Griesemer, Rob Pike, and Ken Thompson. Go's first public release was in March 2012, and it has since grown in popularity among developers due to its simplicity, concurrency, and performance. Today, companies like Google, Uber, Dropbox, and many others use Go to build high-performance, scalable, and reliable software systems, making it one of the fastest-growing programming languages.\n\n## Why GoLang?\n\nThere are several reasons why GoLang should be used to build a program. First and foremost, Go is intended to be fast and efficient and unlike an interpreted language, it has a compiler that generates native machine code and a garbage collector that manages memory automatically, eliminating the need for manual memory management.\n\nSecond, Go has built-in concurrency support, allowing developers to easily write programs that can run multiple tasks or processes at the same time. As a result, Go is an excellent choice for developing high-performance, parallel systems, for example, web servers or networked services.\n\nFurthermore, Go has a simple and concise syntax, making it simple to learn and read. It has an expanding library of open-source packages and tools that can assist developers in developing a wide range of applications.\n\nFinally, Go is supported by a large and active developer community that contributes to the language and helps ensure its ongoing software development and improvement. As a result, Go is an excellent choice for developing efficient, scalable, and dependable software systems.\n\n## Advantages of GoLang\n\nThere are several advantages of using GoLang:\n\n- Go's efficient performance is due to its small memory footprint, quick compilation times, and ability to generate native machine code. As a result, it's ideal for creating high-performance applications like web servers or networked services that can handle a large volume of requests without slowing down.\n- Concurrency is built into Go through Goroutines and channels, allowing developers to write programs that can run multiple tasks or processes simultaneously. This makes creating efficient and scalable systems simple without dealing with the complexities of manually managing threads or processes.\n- Go has a simple and concise syntax that is simple to learn and read. The syntax is similar to C but has certain features like garbage collection and strong typing. This makes it an excellent choice for developers who are new to programming or want to write clean, maintainable code.\n- Its strong and static type system aids in the prevention of common programming errors like null pointer dereferences and buffer overflows. This makes it an excellent choice for developing dependable and secure software, especially in industries such as finance and healthcare, where software errors can have serious consequences.\n- Go has a large and active developer community that contributes to the language and provides a growing Go standard library of open-source packages and tools to help developers build a wide range of applications. Everything from web frameworks and database drivers to machine learning libraries and blockchain tools is included.\n\n## Components of the Golang\n\nThe components of GoLang are:\n\n### Compiler\n\nGoLang's compiler compiles the Go source code into executable files that can be run on a specific platform or architecture. The Go compiler is fast and efficient, producing native machine code for the target platform.\n\n### Standard Library\n\nGoLang includes a comprehensive standard library that includes packages for networking, I/O, text processing, cryptography, and much more. The standard library includes various useful tools and utilities developers can use to create their applications.\n\n### Runtime\n\nGo programming language's runtime includes a garbage collector and a scheduler for managing Goroutines (concurrent functions) and channels (interprocess communication). The Go runtime is in charge of memory management and ensuring that Goroutines are executed in an efficient and predictable manner.\n\n```go\nfunc main() {\n    ch := make(chan int)\n\n    go square(2, ch)\n    go square(3, ch)\n    go square(4, ch)\n\n    fmt.Println(\"Hello World!\")\n    fmt.Println(\u003c-ch)\n    fmt.Println(\u003c-ch)\n    fmt.Println(\u003c-ch)\n}\n\nfunc square(x int, ch chan int) {\n    ch \u003c- x * x\n}\n```\n\nIn this example, we create a channel\n\n```\nch\n```\n\nand call the\n\n```\nsquare()\n```\n\nfunction in parallel using Goroutines. Each\n\n```\nsquare()\n```\n\nfunction call computes the square of a number and returns the result to the channel\n\n```\nch\n```\n\n. The main function receives the channel results and prints them to the console.\n\nLearn to simplify your programs and make your code modular using package main and import:\n\n```go\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n    x := 3\n\n    y := square(x)\n\n    fmt.Println(\"Hello World! The square of %d is %d\\n\", x, y)\n}\n\nfunc square(n int) int {\n    return n * n\n}\n```\n\n### Tools\n\nGoLang programming language includes command-line tools for building, testing, and debugging Go programs. These tools include the Go command for managing Go packages and modules and the Go debugger for debugging Go programs.\n\n### Third-party packages\n\nGo has a large and growing ecosystem of third-party packages and libraries that can be used to extend the language's capabilities. These packages cover web development, machine learning, databases, and other topics.\n\nThese components work together to provide a powerful and flexible programming environment for building efficient, scalable, and reliable software systems.\n\n## Go compiler deep dive\n\nThe Go compiler is a tool that compiles Go source code into executable files that can be run on a specific platform or architecture. The Go compiler is fast and efficient, producing native machine code for the target platform.\n\nThe compiler may be logically split in four phases, which we will briefly describe alongside the list of packages that contain their code.\n\nYou may sometimes hear the terms \"front-end\" and \"back-end\" when referring to the compiler. Roughly speaking, these translate to the first two and last two phases we are going to list here. A third term, \"middle-end\", often refers to much of the work that happens in the second phase.\n\nNote that the `go/_` family of packages, such as go/parser and `go/types`, are mostly unused by the compiler. Since the compiler was initially written in C, the `go/_` packages were developed to enable writing tools working with Go code, such as gofmt and vet. However, over time the compiler's internal APIs have slowly evolved to be more familiar to users of the go/\\* packages.\n\nIt should be clarified that the name \"gc\" stands for \"Go compiler\", and has little to do with uppercase \"GC\", which stands for garbage collection.\n\nThe four phases are:\n\n- Lexing, Parsing and AST generation\n- Type checking\n- SSA generation\n- Machine code generation\n\n![Compilation phases](/docs/assets/compilation-phases.svg)\n\n### Phase 1 - Lexing, Parsing and AST generation\n\nSee diagram below for a visual representation of this phase:\n\n![Lexing, Parsing and AST generation](/docs/assets/lexing-parsing-ast-generation.svg)\n\n**Lexer**\n\nThe first step of every compiler is to break up the raw source code text into tokens, which is done by the scanner (also known as lexer). Tokens can be keywords, strings, variable names, function names, etc. Every valid program “word” is represented by a token. In concrete terms for Go, this might mean we have a token “package”, “main”, “func” and so forth. Each token is represented by its position, type, and raw text in Go.\n\nTo see list of known tokens refer to this code from the go codebase [here](https://github.com/golang/go/blob/master/src/cmd/compile/internal/syntax/tokens.go)\n\nSay that lexer’s is at character `\"`, this could only mean that the current token is a string so the lexer would run the stdString method to verify that the current token is in-fact a string (see inline comments for details):\n\n```go\nfunc (s *scanner) stdString() {\n\tok := true // marks if the string is lexically valid.\n\ts.nextch() // moves the underlying source pointer to the start of the string\n\n\tfor {\n\t\tif s.ch == '\"' {\n\t\t\ts.nextch() // moves the underlying source pointer to the character after\n      '\"'\n\t\t\tbreak\n\t\t}\n\n        // ...\n\n\t\tif s.ch == '\\n' { // an example of an error: standard strings shouldn't contain new line characters\n\t\t\ts.errorf(\"newline in string\")\n\t\t\tok = false // the literal token will be marked as invalid because of the\n      ok value\n\t\t\tbreak\n\t\t}\n\t\tif s.ch \u003c 0 { // we never closed the the opening '\"' and reached EOF\n\t\t\ts.errorAtf(0, \"string not terminated\")\n\t\t\tok = false\n\t\t\tbreak\n\t\t}\n\t\ts.nextch() // everything else goes\n\t}\n\n    // sets the internal scanner state to the current lexer with its value.\n\ts.setLit(StringLit, ok)\n}\n```\n\nGo even allows us to execute the scanner ourselves in a Go program by using the go/scanner and go/token packages. That means we can inspect what our program looks like to the Go compiler after it has been scanned. To do so, we are going to create a simple program that prints all tokens of a Hello World program. The program will look like this:\n\n```go\npackage main\n\nimport (\n  \"fmt\"\n  \"go/scanner\"\n  \"go/token\"\n)\n\nfunc main() {\n  src := []byte(`package main\nimport \"fmt\"\nfunc main() {\n  fmt.Println(\"Hello, world!\")\n}\n`)\n\n  var s scanner.Scanner\n\n  fset := token.NewFileSet()\n  file := fset.AddFile(\"\", fset.Base(), len(src))\n  s.Init(file, src, nil, 0)\n\n  for {\n     pos, tok, lit := s.Scan()\n     fmt.Printf(\"%-6s%-8s%q\\n\", fset.Position(pos), tok, lit)\n\n     if tok == token.EOF {\n        break\n     }\n  }\n}\n```\n\nWe will create our source code string and initialize the scanner.Scanner struct which will scan our source code. We call Scan() as many times as we can and print the token’s position, type, and literal string until we reach the End of File (EOF) marker. When we run the program, it will print the following:\n\n```\n1:1   package \"package\"\n1:9   IDENT   \"main\"\n1:13  ;       \"\\n\"\n2:1   import  \"import\"\n2:8   STRING  \"\\\"fmt\\\"\"\n2:13  ;       \"\\n\"\n3:1   func    \"func\"\n3:6   IDENT   \"main\"\n3:10  (       \"\"\n3:11  )       \"\"\n3:13  {       \"\"\n4:3   IDENT   \"fmt\"\n4:6   .       \"\"\n4:7   IDENT   \"Println\"\n4:14  (       \"\"\n4:15  STRING  \"\\\"Hello, world!\\\"\"\n4:30  )       \"\"\n4:31  ;       \"\\n\"\n5:1   }       \"\"\n5:2   ;       \"\\n\"\n5:3   EOF     \"\"\n```\n\nHere we can see what the Go parser uses when it compiles a program. What we can also see is that the scanner adds semicolons where those would usually be placed in other programming languages such as C. This explains why Go does not need semicolons: they are placed intelligently by the scanner.\n\n**Parsing - AST Generation**\n\nThe parser is (in a very simple terms) a software component that given a source file constructs an AST (Abstract Syntax Tree) from it, which itself is composed of nodes that have a semantic relationship between them according to the language definition.\n\nThe Go compiler defines its list of [nodes](https://github.com/golang/go/blob/master/src/cmd/compile/internal/syntax/nodes.go)\n\nEvery node should adhere to the [Node](https://github.com/golang/go/blob/345184496ce358e663b0150f679d5e5cf1337b41/src/cmd/compile/internal/syntax/nodes.go#L10) interface, which stats that every Node should be able to give it’s position in the source, and to accomplish this, the compiler authors performed a very neat trick of creating a dummy struct that implements the Node interface and added it as an embedded field to all of the other node definitions, this way, they didn’t have to implement the same thing over and over again for every node (neat).\n\nThis trick is used in the same way to mark nodes that are Declarations and those that are Expressions. The linked Go file has all of the node definitions, please take a look (it is very well documented) before continuing.\n\nThe [parser](https://github.com/golang/go/blob/345184496ce358e663b0150f679d5e5cf1337b41/src/cmd/compile/internal/syntax/parser.go#L17) uses the lexer to produce tokens from the given source file, the parsing loop is fairly simple as shown below:\n\n```go\nfor p.tok != _EOF {\n  switch p.tok {\n  case _Const:\n    p.next()\n    f.DeclList = p.appendGroup(f.DeclList, p.constDecl)\n\n  case _Type:\n    p.next()\n    f.DeclList = p.appendGroup(f.DeclList, p.typeDecl)\n\n  case _Var:\n    p.next()\n    f.DeclList = p.appendGroup(f.DeclList, p.varDecl)\n\n  case _Func:\n    p.next()\n    if d := p.funcDeclOrNil(); d != nil {\n      f.DeclList = append(f.DeclList, d)\n    }\n    // ...\n  }\n}\n // ...\nreturn f\n```\n\nParsing a file is as simple as taking the first token of each new top level statement and deciding how to parse that and add it to the children of the current root node (i.e the file).\n\nThe design of the parser itself is based of having for each non-terminal rule a corresponding function that handles parsing that rule specifically, as an example if we take the [ConstDecl](https://github.com/golang/go/blob/5a6a830c1ceafd551937876f11590fd60aea1799/src/cmd/compile/internal/syntax/nodes.go#L66) declaration node, it has a corresponding parsing function in the parser [constDecl](https://github.com/golang/go/blob/5a6a830c1ceafd551937876f11590fd60aea1799/src/cmd/compile/internal/syntax/parser.go#L553), you can expect similar things for other declarations/expressions as well.\n\nFor a better understanding of parsing top level declarations lets walk through an example, the var declaration.\n\nThe Go language allows to declare top level variables using the var keyword, if you are reading this and never seen Golang code before, it looks something like this:\n\n```go\nvar a = 10              // simple declaration\nvar b int               // simple declaration with a type\nvar c, d int            // two variable declaration\nvar e, f int = 10, 12   // two variable declarations with value and types\n```\n\nTo parse this declaration, the parser uses the [varDecl](https://github.com/golang/go/blob/5a6a830c1ceafd551937876f11590fd60aea1799/src/cmd/compile/internal/syntax/parser.go#L703) function:\n\n```go\nfunc (p *parser) varDecl(group *Group) Decl {\n  // ...\n\n\td := new(VarDecl)\n\td.pos = p.pos()\n\td.Group = group\n\td.Pragma = p.takePragma()\n\n\td.NameList = p.nameList(p.name())\n\tif p.gotAssign() {\n\t\td.Values = p.exprList()\n\t} else {\n\t\td.Type = p.type_()\n\t\tif p.gotAssign() {\n\t\t\td.Values = p.exprList()\n\t\t}\n\t}\n\treturn d\n}\n```\n\nSo we start by creating a VarDecl node since this is what we expect to return after this function invocation, we initialize it with some metadata from the parser such as the current position, the [Group](https://github.com/golang/go/blob/69756b38f25bf72f1040dd7fd243febba89017e6/src/cmd/compile/internal/syntax/nodes.go#L118) etc …\n\nWe start by parsing a nameList which takes care of the comma-separated names on the left side of the declaration and from there it’s one of two things: we have a `=` character which means its an initialization with values and we set the values as parsed expression list, or we have a type declaration before and we parse that before trying to parse the actual values of the variables.\n\n_Note about AST nodes_ -\nThe AST nodes defined by the compiler are not the same ones defined in the `ast` module that is used by go tools like `gofmt`.\n\n### Phase 2 - Type checking\n\n- `cmd/compile/internal/types2` (type checking)\n\nThe types2 package is a port of `go/types` to use the syntax package's\nAST instead of `go/ast`.\n\n**IR construction (\"noding\")**\n\n- `cmd/compile/internal/types` (compiler types)\n- `cmd/compile/internal/ir` (compiler AST)\n- `cmd/compile/internal/typecheck` (AST transformations)\n- `cmd/compile/internal/noder` (create compiler AST)\n\nThe compiler middle end uses its own AST definition and representation of Go\ntypes carried over from when it was written in C. All of its code is written in\nterms of these, so the next step after type checking is to convert the syntax\nand types2 representations to ir and types. This process is referred to as\n\"noding.\"\n\nThere are currently two noding implementations:\n\n1. irgen (aka \"-G=3\" or sometimes \"noder2\") is the implementation used starting\n   with Go 1.18, and\n\n2. Unified IR is another, in-development implementation (enabled with\n   `GOEXPERIMENT=unified`), which also implements import/export and inlining.\n\nUp through Go 1.18, there was a third noding implementation (just\n\"noder\" or \"-G=0\"), which directly converted the pre-type-checked\nsyntax representation into IR and then invoked package typecheck's\ntype checker. This implementation was removed after Go 1.18, so now\npackage typecheck is only used for IR transformations.\n\n**Middle end**\n\n- `cmd/compile/internal/deadcode` (dead code elimination)\n- `cmd/compile/internal/inline` (function call inlining)\n- `cmd/compile/internal/devirtualize` (devirtualization of known interface method calls)\n- `cmd/compile/internal/escape` (escape analysis)\n\nSeveral optimization passes are performed on the IR representation:\ndead code elimination, (early) devirtualization, function call\ninlining, and escape analysis.\n\n**Walk**\n\n- `cmd/compile/internal/walk` (order of evaluation, desugaring)\n\nThe final pass over the IR representation is \"walk,\" which serves two purposes:\n\n1. It decomposes complex statements into individual, simpler statements,\n   introducing temporary variables and respecting order of evaluation. This step\n   is also referred to as \"order.\"\n\n2. It desugars higher-level Go constructs into more primitive ones. For example,\n   `switch` statements are turned into binary search or jump tables, and\n   operations on maps and channels are replaced with runtime calls.\n\n### Phase 3 - SSA generation\n\n- `cmd/compile/internal/ssa` (SSA passes and rules)\n- `cmd/compile/internal/ssagen` (converting IR to SSA)\n\nIn this phase, IR is converted into Static Single Assignment (SSA) form, a\nlower-level intermediate representation with specific properties that make it\neasier to implement optimizations and to eventually generate machine code from\nit.\n\nDuring this conversion, function intrinsics are applied. These are special\nfunctions that the compiler has been taught to replace with heavily optimized\ncode on a case-by-case basis.\n\nCertain nodes are also lowered into simpler components during the AST to SSA\nconversion, so that the rest of the compiler can work with them. For instance,\nthe copy builtin is replaced by memory moves, and range loops are rewritten into\nfor loops. Some of these currently happen before the conversion to SSA due to\nhistorical reasons, but the long-term plan is to move all of them here.\n\nThen, a series of machine-independent passes and rules are applied. These do not\nconcern any single computer architecture, and thus run on all `GOARCH` variants.\nThese passes include dead code elimination, removal of\nunneeded nil checks, and removal of unused branches. The generic rewrite rules\nmainly concern expressions, such as replacing some expressions with constant\nvalues, and optimizing multiplications and float operations.\n\n### Phase 4 - Machine code generation\n\n- `cmd/compile/internal/ssa` (SSA lowering and arch-specific passes)\n- `cmd/internal/obj` (machine code generation)\n\nThe machine-dependent phase of the compiler begins with the \"lower\" pass, which\nrewrites generic values into their machine-specific variants. For example, on\namd64 memory operands are possible, so many load-store operations may be combined.\n\nNote that the lower pass runs all machine-specific rewrite rules, and thus it\ncurrently applies lots of optimizations too.\n\nOnce the SSA has been \"lowered\" and is more specific to the target architecture,\nthe final code optimization passes are run. This includes yet another dead code\nelimination pass, moving values closer to their uses, the removal of local\nvariables that are never read from, and register allocation.\n\nOther important pieces of work done as part of this step include stack frame\nlayout, which assigns stack offsets to local variables, and pointer liveness\nanalysis, which computes which on-stack pointers are live at each GC safe point.\n\nAt the end of the SSA generation phase, Go functions have been transformed into\na series of obj.Prog instructions. These are passed to the assembler\n(`cmd/internal/obj`), which turns them into machine code and writes out the\nfinal object file. The object file will also contain reflect data, export data,\nand debugging information.\n\n## Continue learning\n\nNow that you have a basic understanding of go on a high level and the components of go, let's dive into the language itself. We will start with the basics and then move on to more advanced topics. Use the table of contents below to dig deep into different concepts in go.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fendalk200%2Fgo-docs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fendalk200%2Fgo-docs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fendalk200%2Fgo-docs/lists"}