Go is not a class-based object-oriented language. Instead, Go uses Structs to group typed fields together into contiguous memory blocks.
TL;DR (Quick Summary)#
- Struct: A typed collection of fields. Example:
type User struct { Name string; Age int }. - Field Visibility: Capitalized fields (
Name) are Exported (public across packages). Lowercase fields (password) are Unexported (private to current package). - Constructor Function: Idiomatic Go uses factory functions like
NewUser(name string) *Userto instantiate structs safely. - Struct Tags: Metadata annotations (
json:"user_id,omitempty") controlling JSON encoding and decoding via reflection.
1. Declaring Structs & Factory Constructors#
In Go, there are no class keywords or automatic class constructors. The idiomatic pattern is to write a constructor function prefixed with New.
package main
import "fmt"
// User struct definition
type User struct {
ID string // Exported (Public)
Username string // Exported (Public)
email string // Unexported (Private to this package)
}
// Idiomatic Factory Constructor Function
func NewUser(id, username, email string) *User {
return &User{
ID: id,
Username: username,
email: email,
}
}
// Getter method for unexported email field
func (u *User) GetEmail() string {
return u.email
}
func main() {
// Instantiate via Constructor
u := NewUser("usr_100", "rachmat", "[email protected]")
fmt.Printf("User ID: %s, Name: %s\n", u.ID, u.Username)
fmt.Printf("Private Email: %s\n", u.GetEmail())
}2. Anonymous Structs & Struct Literals#
For one-off data structures (like test cases or single HTTP response payloads), you can declare Anonymous Structs without defining a type name.
package main
import "fmt"
func main() {
// Anonymous struct declaration and inline initialization
config := struct {
Environment string
Port int
}{
Environment: "production",
Port: 8080,
}
fmt.Printf("Config: %s on port %d\n", config.Environment, config.Port)
}3. Serialization with Struct Tags (json:"...")#
Struct Tags provide runtime metadata annotations processed by reflection (such as encoding/json or gorm).
package main
import (
"encoding/json"
"fmt"
)
type Product struct {
ID int `json:"product_id"`
Name string `json:"name"`
Price float64 `json:"price"`
Discount float64 `json:"discount,omitempty"` // Omit key if 0.0
internalSKU string `json:"-"` // Completely ignore in JSON
}
func main() {
p1 := Product{
ID: 501,
Name: "Mechanical Keyboard",
Price: 150.00,
Discount: 0.0, // Zero value -> will be omitted in JSON!
internalSKU: "SKU-999-SECRET",
}
// Marshal struct to formatted JSON bytes
jsonData, _ := json.MarshalIndent(p1, "", " ")
fmt.Println(string(jsonData))
}Expected Terminal Output:
{
"product_id": 501,
"name": "Mechanical Keyboard",
"price": 150
}Notice discount was omitted because of omitempty, and internalSKU was ignored because it is an unexported private field!
4. Struct Memory Alignment & Padding (Advanced)#
Field ordering inside a struct impacts its overall memory footprint on 64-bit CPU architectures due to Memory Alignment (Padding).
// 🔴 Bad Field Alignment: Size = 24 bytes (Due to 7 bytes padding after bool!)
type BadStruct struct {
FlagA bool // 1 byte
Value int64 // 8 bytes
FlagB bool // 1 byte
}
// 🟢 Optimized Field Alignment: Size = 16 bytes (Fields grouped by word size!)
type GoodStruct struct {
Value int64 // 8 bytes
FlagA bool // 1 byte
FlagB bool // 1 byte
}Summary & Next Steps#
In this episode:
- We declared Go Structs and written idiomatic
NewUser()constructor functions. - We controlled field visibility (Exported vs Unexported).
- We serialized structs using JSON field tags (
json:"name,omitempty"). - We analyzed struct memory padding optimization.
Check the rest of the Go Master Series in content/series/go/!

