Golang

My notes about Golang


Additional sources for learning and practice:


Go Tooling


arguments and outputs


Text formatting



Error handling

About Go's "guard clauses" arrow-up-right

How to output errors

import "errors"


Data Types

What kinds, how to define empty data types

Variable naming conventions

What is nil?

Shallow copies vs deep copies

Empty interface{}


Functions with explanations of syntactic sugar

Return values

functions naming conventions

what empty return statement returns

Anonymous functions


Functions vs Methods (general comparison)

  • Binding

    • Functions: free, not attached to any type.

    • Methods: attached to a receiver type; define that type’s behavior.

  • Syntax

    • Functions: Do(x, y).

    • Methods: x.Do(y)—reads as “x does Do.”

  • Interfaces

    • Functions: do not count toward interface satisfaction.

    • Methods: method sets determine whether a type implements an interface.

  • Encapsulation

    • Functions: can’t directly express “behavior of T.”

    • Methods: group behavior with data; can operate on unexported fields within the same package, aiding encapsulation and discoverability.

  • Namespacing/Discovery

    • Functions: live in package namespace (pkg.Foo).

    • Methods: live on the type (t.Foo()), making APIs easier to explore via the type.

  • Overloading/Dispatch

    • Go has no function overloading. Methods allow distinct operations with the same name across different types (e.g., many types can have String()).

  • Constructors/Helpers

    • Constructors are functions (e.g., NewThing(...)).

    • Behavior is usually methods (e.g., thing.Do()).

Rule of thumb:

  • If it’s an operation conceptually “about” a type, make it a method.

  • If it’s a general utility or factory that doesn’t need a receiver, make it a function.


Pointers

General description:

Referencing in function signature

Dereferencing

Pointer receiver vs value receiver

Using a pointer receiver (e.g. *Config) is the right choice when:

  • You want to modify the struct's fields

  • The struct is large and you want to avoid copying

  • You want all methods to have a consistent receiver type

Example

Key takeaways:

  • Calling a pointer-receiver method on a value is allowed; Go uses &value.

  • Passing a struct by value creates a copy; any mutations (even via pointer-receiver methods on that copy) don’t affect the original.

  • Passing a pointer lets mutations affect the original.

Another example herearrow-up-right just in case.


Using pointers with functions vs methods

  • Functions:

    • Not tied to a type.

    • You pass arguments explicitly (value or pointer).

    • Don’t participate in interface satisfaction.

    • Example:

  • Methods:

    • Bound to a receiver type (value or pointer).

    • Called with receiver syntax; Go can auto-take address/deref.

    • Define a type’s behavior and determine interface satisfaction.

    • Example:

How to choose between the two:

  • If it’s behavior of the type (good for interfaces/encapsulation), use methods.

  • If it’s a general operation not tied to a type, use a function.

  • Use pointer receivers when the method mutates state or the type is large/contains sync primitives. Use value receivers for small, immutable-like types.


Copies in Go (short and sharp):

  • Assignment copies values: v2 = v1 makes a shallow copy of the struct’s fields.

  • Passing by value copies: func f(s T) gets a copy of s. Mutations inside f don’t affect the caller.

  • Pointer avoids copying: func f(s *T) passes a reference; mutations affect the original.

  • Shallow copy means referenced fields (like slices, maps, pointers) are copied as descriptors, pointing to the same underlying data. So:

    • Copying a slice copies its header (ptr, len, cap) but not its backing array. Appending may reallocate and diverge; mutating elements before reallocation affects both “copies.”

    • Maps are reference types; copying a map variable copies the header pointing to the same map. Mutations affect both.

  • Concurrency: copying structs with sync.Mutex (as in http.Server) is dangerous—copying a mutex is a bug. Prefer pointers to avoid accidental copies.

  • Performance: large structs are costly to copy; pointers reduce allocation/copying at the cost of potential shared-state complexity.

Rules of thumb for when to use pointers:

  • Small, immutable-like data: pass by value.

  • Large structs, types with interior mutability (mutexes, pools), or you need shared state: use pointers.


Goroutines and channels


Mutexes


Generics


Panic


Last updated