Go Tutorials: Go Functions Master Guide

A function is one of the most important building blocks in Go.

If you understand functions properly, concepts such as methods, interfaces, goroutines, error handling, defer, callbacks, HTTP handlers, and concurrency become much easier.

The best mental model is:

INPUT
  ↓
FUNCTION
  ↓
WORK
  ↓
OUTPUT

For example:

func add(a int, b int) int {
    return a + b
}
a = 10 ─┐
        ├──► add() ───► 30
b = 20 ─┘

1. What is a Function?

A function is a named block of reusable code that performs a task.

Instead of writing:

fmt.Println(10 + 20)
fmt.Println(30 + 40)
fmt.Println(50 + 60)

you can create:

func add(a int, b int) int {
    return a + b
}

and reuse it:

add(10, 20)
add(30, 40)
add(50, 60)

Why use functions?

Functions help you:

  • avoid duplicate code
  • divide large programs into small pieces
  • reuse logic
  • test code more easily
  • make code easier to understand

2. Basic Function

Let’s start with the simplest possible function.

package main

import "fmt"

func greet() {
    fmt.Println("Hello!")
}

func main() {
    greet()
}

Output:

Hello!

Understand it

func greet() {

means:

func
 │
 └── create a function

greet
 │
 └── function name

()
 │
 └── no input parameters

The body is:

{
    fmt.Println("Hello!")
}

And:

greet()

means:

Execute the greet function.


3. Function With One Parameter

Functions can receive information.

package main

import "fmt"

func greet(name string) {
    fmt.Println("Hello", name)
}

func main() {
    greet("Rajesh")
}

Output:

Hello Rajesh

Here:

func greet(name string)

means:

name     string
 │         │
 │         └── data type
 │
 └── parameter name

When you call:

greet("Rajesh")

then:

name = "Rajesh"

4. Parameter vs Argument

This terminology is useful.

Function definition:

func greet(name string)

name is a parameter.

Function call:

greet("Rajesh")

"Rajesh" is an argument.

Think:

Parameter = variable declared by function
Argument  = actual value sent to function

5. Multiple Parameters

A function can receive multiple values.

package main

import "fmt"

func add(a int, b int) {
    fmt.Println(a + b)
}

func main() {
    add(10, 20)
}

Output:

30

The values are mapped by position:

add(10, 20)

     │   │
     │   └── b = 20
     │
     └────── a = 10

6. Short Parameter Syntax

Instead of:

func add(a int, b int)

Go allows:

func add(a, b int)

because both parameters have the same type.

Example:

package main

import "fmt"

func add(a, b int) {
    fmt.Println(a + b)
}

func main() {
    add(10, 20)
}

Both versions mean exactly the same thing.


7. Function Returning a Value

Functions can return results.

package main

import "fmt"

func add(a, b int) int {
    return a + b
}

func main() {

    result := add(10, 20)

    fmt.Println(result)
}

Output:

30

Look at:

func add(a, b int) int

The final:

int

means:

This function returns an integer.

And:

return a + b

sends the result back.

Flow:

10 ──┐
     ├──► add() ───► 30
20 ──┘

8. Return Value Directly

You don’t always need another variable.

Instead of:

result := add(10, 20)

fmt.Println(result)

you can write:

fmt.Println(add(10, 20))

Complete example:

package main

import "fmt"

func add(a, b int) int {
    return a + b
}

func main() {
    fmt.Println(add(10, 20))
}

9. Multiple Return Values

Go functions can return multiple values.

This is extremely common in Go.

package main

import "fmt"

func calculate(a, b int) (int, int) {

    sum := a + b
    product := a * b

    return sum, product
}

func main() {

    sum, product := calculate(10, 20)

    fmt.Println("Sum:", sum)
    fmt.Println("Product:", product)
}

Output:

Sum: 30
Product: 200

This:

(int, int)

means:

first result  → int
second result → int

And:

return sum, product

returns both.


10. Ignoring a Return Value With _

Suppose:

func calculate(a, b int) (int, int)

returns:

sum
product

but you only want the sum.

Use _.

package main

import "fmt"

func calculate(a, b int) (int, int) {
    return a + b, a * b
}

func main() {

    sum, _ := calculate(10, 20)

    fmt.Println(sum)
}

Output:

30

_ is called the blank identifier.

It means:

I received this value but don’t need it.


11. Named Return Values

Go allows return variables to be named.

For example:

func calculate(a, b int) (sum int, product int) {

    sum = a + b
    product = a * b

    return
}

Complete example:

package main

import "fmt"

func calculate(a, b int) (sum int, product int) {

    sum = a + b
    product = a * b

    return
}

func main() {

    sum, product := calculate(10, 20)

    fmt.Println(sum)
    fmt.Println(product)
}

Output:

30
200

Notice:

return

has no values.

That’s because sum and product were already declared as return variables.

Should you use named returns?

They can be useful in small functions, but don’t overuse them.

This is usually clearer:

return sum, product

than:

return

especially in larger functions.


12. Functions and Pass-by-Value

This is extremely important.

Go passes function arguments by value.

Example:

package main

import "fmt"

func changeNumber(number int) {

    number = 100

    fmt.Println("Inside:", number)
}

func main() {

    number := 10

    changeNumber(number)

    fmt.Println("Outside:", number)
}

Output:

Inside: 100
Outside: 10

Why?

Because Go creates a copy.

Conceptually:

main()

number = 10
    │
    │ copy
    ▼

changeNumber()

number = 10

number = 100

The original variable is untouched.

So:

Original
number = 10

Copy inside function
number = 100

This is one of the fundamental rules of Go:

Go passes arguments by value.


13. Pointer Parameters

What if the function really needs to change the original variable?

Use a pointer.

package main

import "fmt"

func changeNumber(number *int) {

    *number = 100
}

func main() {

    number := 10

    changeNumber(&number)

    fmt.Println(number)
}

Output:

100

Two important operators are involved:

OperatorMeaning
&get address
*access value at address

So:

&number

means:

Give me the memory address of number.

And:

*number

inside the function means:

Access the value stored at that address.

Conceptually:

main

number = 10
   │
   │ address
   ▼
0x1000


changeNumber()

number
   │
   └────────► 0x1000
                  │
                  ▼
               original
               number

Then:

*number = 100

changes the original.


14. Incrementing Through a Pointer

Your earlier example contained:

(*callCount)++

Example:

package main

import "fmt"

func increment(count *int) {
    (*count)++
}

func main() {

    calls := 0

    increment(&calls)

    fmt.Println(calls)
}

Output:

1

Breaking it down:

&calls

means:

Address of calls.

count

stores that address.

*count

means:

Value stored at the address.

Then:

(*count)++

means:

Increase that original value by 1.


15. Variadic Functions — ...

A function sometimes needs an unknown number of arguments.

Go provides variadic functions.

package main

import "fmt"

func total(numbers ...int) int {

    sum := 0

    for _, number := range numbers {
        sum += number
    }

    return sum
}

func main() {

    fmt.Println(total(10))
    fmt.Println(total(10, 20))
    fmt.Println(total(10, 20, 30))
}

Output:

10
30
60

This:

numbers ...int

means:

Accept zero or more integers.

Inside the function, numbers behaves like a slice:

[10, 20, 30]

16. Variadic Parameter Must Be Last

This is valid:

func calculate(name string, numbers ...int)

This is invalid:

func calculate(numbers ...int, name string)

Rule:

A variadic parameter must always be the final parameter.


17. Passing a Slice to a Variadic Function

Suppose:

numbers := []int{10, 20, 30}

You can pass the slice using:

numbers...

Example:

package main

import "fmt"

func total(numbers ...int) int {

    sum := 0

    for _, number := range numbers {
        sum += number
    }

    return sum
}

func main() {

    numbers := []int{10, 20, 30}

    result := total(numbers...)

    fmt.Println(result)
}

Output:

60

Notice the difference:

numbers

is a slice.

numbers...

means:

Expand the slice into individual arguments.

Conceptually:

total(numbers...)

becomes:

total(10, 20, 30)

18. Your summarize() Function

Now your original function becomes much easier to understand.

func summarize(
    label string,
    callCount *int,
    scores ...int,
) (string, int) {

    (*callCount)++

    total := 0

    for _, score := range scores {
        total += score
    }

    return strings.ToUpper(label), total
}

It contains:

                 summarize
                     │
      ┌──────────────┼──────────────┐
      │              │              │
      ▼              ▼              ▼
 normal param    pointer param   variadic param

label string    callCount *int   scores ...int

And returns:

(string, int)

Complete flow:

summarize(
    "team score",
    &calls,
    10, 20, 30,
)

        │
        ▼

label
"team score"

callCount
points to calls

scores
[10,20,30]

        │
        ▼

calls++
calls = 1

        │
        ▼

10 + 20 + 30
total = 60

        │
        ▼

strings.ToUpper("team score")
"TEAM SCORE"

        │
        ▼

return

"TEAM SCORE", 60

19. Functions Can Call Other Functions

Functions aren’t isolated.

One function can call another.

package main

import "fmt"

func add(a, b int) int {
    return a + b
}

func printResult(a, b int) {

    result := add(a, b)

    fmt.Println(result)
}

func main() {
    printResult(10, 20)
}

Flow:

main()
   │
   ▼
printResult()
   │
   ▼
add()
   │
   ▼
30

This is how real applications are built: many small functions working together.


20. Functions Are Values in Go

This is an important feature.

A function can be stored inside a variable.

package main

import "fmt"

func add(a, b int) int {
    return a + b
}

func main() {

    operation := add

    result := operation(10, 20)

    fmt.Println(result)
}

Output:

30

Here:

operation := add

doesn’t execute add.

It stores the function.

Then:

operation(10, 20)

executes it.


21. Function Type

Functions themselves have types.

For this function:

func add(a int, b int) int

the function type is:

func(int, int) int

Example:

package main

import "fmt"

func add(a, b int) int {
    return a + b
}

func main() {

    var operation func(int, int) int

    operation = add

    fmt.Println(operation(10, 20))
}

Output:

30

22. Passing a Function Into Another Function

Because functions are values, you can pass them into other functions.

This is called a higher-order function.

package main

import "fmt"

func add(a, b int) int {
    return a + b
}

func calculate(
    a int,
    b int,
    operation func(int, int) int,
) int {

    return operation(a, b)
}

func main() {

    result := calculate(10, 20, add)

    fmt.Println(result)
}

Output:

30

Flow:

calculate
   │
   ├── 10
   ├── 20
   │
   └── add function
          │
          ▼
      add(10,20)
          │
          ▼
         30

This pattern is used heavily for:

  • callbacks
  • HTTP handlers
  • middleware
  • sorting
  • concurrency
  • event processing

23. Anonymous Functions

A function doesn’t always need a name.

This is called an anonymous function.

package main

import "fmt"

func main() {

    add := func(a, b int) int {
        return a + b
    }

    result := add(10, 20)

    fmt.Println(result)
}

Output:

30

Here:

func(a, b int) int {
    return a + b
}

has no name.

It is assigned to:

add

24. Immediately Executed Anonymous Function

You can also execute an anonymous function immediately.

package main

import "fmt"

func main() {

    func() {
        fmt.Println("Hello")
    }()
}

Notice:

}()

The final () executes the function immediately.


25. Closures

A closure is an anonymous function that remembers variables outside itself.

Example:

package main

import "fmt"

func main() {

    count := 0

    increment := func() {

        count++

        fmt.Println(count)
    }

    increment()
    increment()
    increment()
}

Output:

1
2
3

The function can access:

count

even though count was created outside the function.

Conceptually:

count = 0
   ▲
   │
increment()
   │
   ├── count++
   └── remembers count

Closures are commonly used in:

  • callbacks
  • middleware
  • configuration
  • state management
  • goroutines

26. Function Returning Another Function

A function can even return another function.

package main

import "fmt"

func createMultiplier(multiplier int) func(int) int {

    return func(number int) int {
        return number * multiplier
    }
}

func main() {

    double := createMultiplier(2)

    fmt.Println(double(10))
    fmt.Println(double(20))
}

Output:

20
40

double remembers:

multiplier = 2

This is another closure example.


27. Callback Functions

A callback is simply:

A function passed to another function so it can be called later.

Example:

package main

import "fmt"

func process(number int, callback func(int)) {

    result := number * 2

    callback(result)
}

func printResult(result int) {

    fmt.Println("Result:", result)
}

func main() {

    process(10, printResult)
}

Output:

Result: 20

Flow:

main
 │
 ▼
process(10, printResult)
 │
 ├── 10 × 2
 │
 ▼
20
 │
 ▼
printResult(20)

28. Returning Errors From Functions

This is perhaps the most common Go function pattern.

Instead of exceptions, Go commonly returns:

value + error

Example:

package main

import (
    "errors"
    "fmt"
)

func divide(a, b float64) (float64, error) {

    if b == 0 {
        return 0, errors.New("cannot divide by zero")
    }

    return a / b, nil
}

func main() {

    result, err := divide(10, 2)

    if err != nil {
        fmt.Println("Error:", err)
        return
    }

    fmt.Println(result)
}

Output:

5

Function:

func divide(a, b float64) (float64, error)

returns:

result
error

This pattern appears everywhere in Go:

value, err := someFunction()

29. Early Return

Go code commonly uses early returns.

Instead of:

if something {
    // lots of logic
}

you often see:

if invalid {
    return
}

Example:

package main

import "fmt"

func checkAge(age int) {

    if age < 18 {
        fmt.Println("Not allowed")
        return
    }

    fmt.Println("Allowed")
}

func main() {

    checkAge(20)
}

Output:

Allowed

This style keeps Go code simple and flat.


30. defer Inside Functions

defer means:

Execute this function when the current function is about to finish.

Example:

package main

import "fmt"

func demo() {

    defer fmt.Println("Goodbye")

    fmt.Println("Hello")
}

func main() {
    demo()
}

Output:

Hello
Goodbye

Although:

defer fmt.Println("Goodbye")

appears first, it runs when demo() finishes.

Flow:

demo()
 │
 ├── register deferred function
 │
 ├── print Hello
 │
 └── finishing
        │
        ▼
     print Goodbye

defer is commonly used for cleanup:

file.Close()
rows.Close()
mutex.Unlock()

31. Multiple defer Calls

Deferred functions run in reverse order.

package main

import "fmt"

func main() {

    defer fmt.Println("One")
    defer fmt.Println("Two")
    defer fmt.Println("Three")
}

Output:

Three
Two
One

Think of a stack:

defer One
defer Two
defer Three

finish function

Three
Two
One

32. Recursive Functions

A recursive function calls itself.

Example:

package main

import "fmt"

func countdown(number int) {

    if number == 0 {
        return
    }

    fmt.Println(number)

    countdown(number - 1)
}

func main() {

    countdown(5)
}

Output:

5
4
3
2
1

Flow:

countdown(5)
    ↓
countdown(4)
    ↓
countdown(3)
    ↓
countdown(2)
    ↓
countdown(1)
    ↓
countdown(0)
    ↓
return

This condition:

if number == 0 {
    return
}

is called the base case.

Without a base case, recursion would continue until the program fails.


33. Methods vs Functions

This distinction is extremely important.

Normal function:

func greet(name string) {
}

Method:

func (user User) greet() {
}

A method belongs to a type.

Example:

package main

import "fmt"

type User struct {
    Name string
}

func (user User) Greet() {

    fmt.Println("Hello", user.Name)
}

func main() {

    user := User{
        Name: "Rajesh",
    }

    user.Greet()
}

Output:

Hello Rajesh

The special part is:

(user User)

This is called the receiver.

Think:

FUNCTION

greet(user)


METHOD

user.Greet()

34. Pointer Receiver Methods

A method that needs to change the original struct usually uses a pointer receiver.

package main

import "fmt"

type User struct {
    Name string
}

func (user *User) ChangeName(name string) {

    user.Name = name
}

func main() {

    user := User{
        Name: "Rajesh",
    }

    user.ChangeName("Kumar")

    fmt.Println(user.Name)
}

Output:

Kumar

Pointer receiver:

func (user *User)

allows modification of the original User.


35. Function vs Method

FeatureFunctionMethod
Belongs to typeNoYes
Has receiverNoYes
Called asadd()user.Greet()
Can receive parametersYesYes
Can return valuesYesYes
Can be variadicYesYes
Can return errorsYesYes
Can use pointersYesYes

Example:

add(10, 20)

versus:

user.Greet()

36. Generic Functions

Modern Go supports generics.

Suppose you want an add function that works with both integers and floats.

You can write:

package main

import "fmt"

func add[T int | float64](a, b T) T {

    return a + b
}

func main() {

    fmt.Println(add(10, 20))

    fmt.Println(add(10.5, 20.5))
}

Output:

30
31

Here:

[T int | float64]

means:

T may be an int or float64.

Then:

a, b T

means both parameters use that type.

Generics are useful, but I recommend learning ordinary functions thoroughly before going deep into them.


37. main() Is Also a Function

Your Go program starts with:

func main()

Example:

package main

import "fmt"

func main() {

    fmt.Println("Hello")
}

main() is special because in a runnable Go program:

Operating System
      │
      ▼
Go program
      │
      ▼
main()

The program starts executing from main() in package main.


38. init() Function

Go also has a special function named:

init()

Example:

package main

import "fmt"

func init() {

    fmt.Println("init")
}

func main() {

    fmt.Println("main")
}

Output:

init
main

init() executes before main().

Usually it is used sparingly for package initialization.


39. Functions Cannot Be Overloaded in Go

Languages such as Java support:

add(int, int)

add(float, float)

with the same function name.

Go does not support traditional function overloading.

You cannot write:

func add(a int, b int) {
}

func add(a float64, b float64) {
}

because both functions are named add.

Usually you:

  • use different function names
  • use interfaces
  • use generics

depending on the situation.


40. Go Has No Default Function Parameters

Some languages allow:

greet(name="Rajesh")

Go doesn’t support default parameters directly.

You normally make them explicit.

For example:

func greet(name string) {
}

and call:

greet("Rajesh")

41. Go Has No Optional Parameters Directly

Go doesn’t have standard optional arguments like Python.

But variadic arguments sometimes provide similar behavior:

func log(messages ...string)

You can call:

log()

or:

log("hello")

or:

log("hello", "world")

For complex configuration, Go often uses structs or the functional options pattern.

That’s an advanced topic for later.


42. Function Scope

Variables created inside a function normally exist only inside that function.

Example:

package main

import "fmt"

func test() {

    message := "Hello"

    fmt.Println(message)
}

func main() {

    test()
}

You cannot access:

message

directly from main().

Because its scope belongs to:

test()

Conceptually:

main scope
│
│
└── test scope
      │
      └── message

43. Local vs Package-Level Variables

Variable outside a function:

var count = 10

is package-level.

Example:

package main

import "fmt"

var count = 10

func show() {

    fmt.Println(count)
}

func main() {

    show()
}

Output:

10

Functions inside the package can access count.

But generally, prefer passing data to functions rather than relying heavily on global/package variables.


44. Exported Functions

In Go, capitalization controls package visibility.

Lowercase:

func calculate()

means:

Only accessible within the same package.

Uppercase:

func Calculate()

means:

Exported and accessible from other packages.

Example:

calculator.Add()

Here Add needs to start with a capital letter if another package uses it.

This Go rule applies to:

  • functions
  • methods
  • structs
  • fields
  • interfaces
  • variables
  • constants

45. Function Signature

You will often hear the term function signature.

Example:

func add(a int, b int) int

Important parts are essentially:

function name
parameters
parameter types
return types

Example:

add(int, int) → int

Another:

func summarize(
    label string,
    callCount *int,
    scores ...int,
) (string, int)

You can mentally read its signature as:

summarize(
    string,
    pointer-to-int,
    many-int
)
→
(string, int)

46. Function Anatomy — Master View

Consider:

func summarize(label string, callCount *int, scores ...int) (string, int) {
    // body
}

The anatomy is:

func summarize(label string, callCount *int, scores ...int) (string, int)
 │       │          │             │              │             │
 │       │          │             │              │             │
 │       │          │             │              │             └ return types
 │       │          │             │              │
 │       │          │             │              └ variadic parameter
 │       │          │             │
 │       │          │             └ pointer parameter
 │       │          │
 │       │          └ normal parameter
 │       │
 │       └ function name
 │
 └ function declaration

47. The Most Important Function Patterns

You will see these constantly.

No input, no output

func hello() {
}

Input, no output

func hello(name string) {
}

Input and output

func add(a, b int) int {
    return a + b
}

Multiple outputs

func calculate(a, b int) (int, int) {
    return a + b, a * b
}

Value + error

func load() (string, error) {
}

Pointer parameter

func update(value *int) {
}

Variadic

func total(values ...int) int {
}

Function parameter

func calculate(
    operation func(int, int) int,
) {
}

Method

func (user User) Greet() {
}

Pointer receiver method

func (user *User) Update() {
}

48. Master Comparison Table

ConceptSyntaxPurpose
Basic functionfunc hello()reusable code
Parametername stringsend data
Multiple parametersa, b intsend multiple values
Returnfunc f() intreturn result
Multiple return(int, string)return multiple values
Named return(result int)name result variable
Blank identifier_ignore value
Pointer parametervalue *intmodify indirectly
Address&valueget memory address
Dereference*ptraccess pointed value
Variadicvalues ...intany number of arguments
Slice expansionvalues...pass slice as arguments
Anonymous functionfunc() {}unnamed function
Closureanonymous function + outer variablepreserve/access state
Function variablef := addstore function
Function parameterfunc(int) intcallback
Higher-order functionfunction receives/returns functionflexible behavior
Recursionfunction calls itselfrecursive problems
deferdefer cleanup()run when function exits
Methodfunc (x T) F()function associated with type
Pointer receiverfunc (x *T) F()mutate receiver
Generic functionfunc F[T ...]work with multiple types
Exported functionfunc Add()accessible from packages
main()func main()program entry
init()func init()package initialization

49. What You Should Learn First

Don’t try to master everything simultaneously.

Learn functions in this order:

LEVEL 1
│
├── Basic function
├── Parameters
├── Return values
└── Multiple returns
       │
       ▼
LEVEL 2
│
├── Pass by value
├── Pointers
├── Blank identifier
└── Variadic parameters
       │
       ▼
LEVEL 3
│
├── Anonymous functions
├── Function variables
├── Callbacks
└── Closures
       │
       ▼
LEVEL 4
│
├── defer
├── recursion
├── errors
└── function types
       │
       ▼
LEVEL 5
│
├── Methods
├── Pointer receivers
├── Interfaces
└── Generics

50. The 10 Rules I Would Memorize

If you’re learning Go, these ten rules cover most function confusion:

  1. A function is created using:
func
  1. Parameters go inside:
()
  1. Return type comes after the parameters:
func add(a, b int) int
  1. Multiple values can be returned:
func f() (int, string)
  1. _ means:
ignore this value
  1. Go passes arguments by value.
  2. &x means:
address of x
  1. *ptr means:
value at that address
  1. ...int means:
zero or more integers
  1. A method is basically a function with a receiver:
func (user User) Greet()

51. One Final Example Combining the Important Concepts

Now revisit your example:

package main

import (
    "fmt"
    "strings"
)

func summarize(
    label string,
    callCount *int,
    scores ...int,
) (string, int) {

    // Modify the original calls variable
    (*callCount)++

    // Create total
    total := 0

    // Loop through all scores
    for _, score := range scores {

        // Add each score
        total += score
    }

    // Return two values
    return strings.ToUpper(label), total
}

func main() {

    calls := 0

    label, total := summarize(
        "team score",
        &calls,
        10,
        20,
        30,
    )

    fmt.Println(label)
    fmt.Println("Total:", total)
    fmt.Println("Function calls:", calls)
}

Output:

TEAM SCORE
Total: 60
Function calls: 1

This tiny program demonstrates:

✓ function declaration

✓ normal parameter
    label string

✓ pointer parameter
    callCount *int

✓ variadic parameter
    scores ...int

✓ multiple return values
    (string, int)

✓ pointer dereferencing
    (*callCount)++

✓ local variable
    total := 0

✓ range loop
    range scores

✓ blank identifier
    _

✓ return
    return ...

✓ calling another package's function
    strings.ToUpper()

✓ receiving multiple values
    label, total := ...

✓ address operator
    &calls

The master mental model

Whenever you see a Go function, don’t try to understand the entire line at once.

Read it in this order:

1. What is the function called?

2. What goes IN?

3. Does anything use a pointer?

4. Is anything variadic?

5. What happens inside?

6. What comes OUT?

For example:

func summarize(
    label string,
    callCount *int,
    scores ...int,
) (string, int)

read it as:

NAME
│
└── summarize

INPUT
│
├── label      → string
├── callCount  → pointer to int
└── scores     → many integers

OUTPUT
│
├── string
└── int

Once you develop this habit, even complicated Go function declarations become much easier to read.

Related Posts

Go Tutorials: Go Methods

Go methods become much easier once you understand one idea: A method is simply a function attached to a type. And the important rule is: A receiver…

Read More

Go Tutorials: Modules, Packages, Subpackages, Submodules, and Workspaces

This tutorial gives you one complete mental model for: The most important idea is: And sometimes: These two designs are very different. 1. What is a Go…

Read More

Go Tutorials: Numeric Types Beginner Tutorial

Go has four main families of numeric types: The simplest way to remember them is: Type family Stores Example int Whole numbers, positive or negative -10, 0,…

Read More

Go Tutorials: Go Testing, Benchmarking, and Profiling

These three topics become much easier once you separate the questions they answer: Topic Main question Main Go tool Result Testing Does my code work correctly? go…

Read More

Go Tutorials: Generics

1. What are Generics? Generics let you write one piece of code that works with multiple types while keeping Go’s compile-time type safety. Suppose you want a…

Read More

Go Concurrency Management Made Simple

This tutorial covers: The goal is: One concept → one purpose → one complete runnable example. Every example is independent. Save any example as: and run: 0….

Read More