Go Structs

Ma Mahalakshmi V Updated 04 Nov 2026
4 min read

Go Structs

A struct (short for "structure") is a composite data type that groups related fields together, even when those fields have different types. Where an array or slice holds many values of the same type, a struct lets you bundle values of different types into one meaningful, named unit.

Structs are how Go models real-world entities — a user, a product, an order — without needing a class system.

Why Use Structs?

  • Group related data into a single variable instead of tracking many separate ones.
  • Represent a data model clearly and self-documentingly.
  • Improve readability and maintainability as programs grow.
  • Provide a foundation for structured data handling in functions and, later, methods.

Declaring a Struct

type StructName struct {
    field1 datatype
    field2 datatype
    field3 datatype
}

type introduces a new named type; struct { ... } defines its shape.

Defining and Using a Struct

package main

import "fmt"

// Define a struct
type Student struct {
    name   string
    age    int
    course string
    grade  float64
}

func main() {
    // Create struct instances (zero-valued at first)
    var s1 Student
    var s2 Student

    // Assign values to s1
    s1.name = "Rahul"
    s1.age = 20
    s1.course = "Computer Science"
    s1.grade = 8.7

    // Assign values to s2
    s2.name = "Anita"
    s2.age = 22
    s2.course = "Electronics"
    s2.grade = 9.1

    // Access and print struct fields
    fmt.Println("Student 1:", s1.name, s1.age, s1.course, s1.grade)
    fmt.Println("Student 2:", s2.name, s2.age, s2.course, s2.grade)
}

Expected output:

Student 1: Rahul 20 Computer Science 8.7
Student 2: Anita 22 Electronics 9.1

var s1 Student creates a struct whose fields all start at their type's zero value ("" for name and course, 0 for age, 0.0 for grade) — a struct is never left in an undefined state, the same guarantee Go gives ordinary variables.

Accessing Struct Fields

Struct fields are read and written using the dot (.) operator:

s1.name
s1.age

A Faster Way to Create Struct Values: Struct Literals

Setting each field individually with var plus dot-assignment works, but it's verbose. Go's struct literal syntax lets you build and populate a struct in one expression — this is the form you'll see most often in real code:

package main

import "fmt"

type Student struct {
    name   string
    age    int
    course string
    grade  float64
}

func main() {
    // Positional struct literal — values must match field order exactly
    s1 := Student{"Rahul", 20, "Computer Science", 8.7}

    // Keyed struct literal — order doesn't matter, and fields can be omitted
    s2 := Student{name: "Anita", course: "Electronics", grade: 9.1}

    fmt.Println("Student 1:", s1)
    fmt.Println("Student 2:", s2)
}

Expected output:

Student 1: {Rahul 20 Computer Science 8.7}
Student 2: {Anita 0 Electronics 9.1}

Notice s2.age defaults to 0 because it was left out of the keyed literal — any field you don't mention simply keeps its zero value.

Best practice: prefer the keyed form (Student{name: "Anita", ...}) over the positional form in real code. It's self-documenting, and — critically — it keeps working correctly if someone later reorders or adds fields to the Student type, whereas a positional literal would silently assign values to the wrong fields.

Passing Structs to Functions

Structs can be passed as function arguments, letting you write logic that operates on structured data.

package main

import "fmt"

type Product struct {
    name  string
    price float64
    stock int
}

// Function that accepts a struct
func displayProduct(p Product) {
    fmt.Println("Product:", p.name)
    fmt.Println("Price:", p.price)
    fmt.Println("Stock:", p.stock)
    fmt.Println("---")
}

func main() {
    p1 := Product{"Laptop", 59999.99, 10}
    p2 := Product{"Headphones", 1999.50, 50}

    displayProduct(p1)
    displayProduct(p2)
}

Expected output:

Product: Laptop
Price: 59999.99
Stock: 10
---
Product: Headphones
Price: 1999.5
Stock: 50
---

Important: structs are passed by value. When p1 is passed into displayProduct, Go copies the entire struct — any change displayProduct made to p.stock would not affect p1 in main. This mirrors how arrays behave, and it's a deliberate design choice: it means a function can never accidentally mutate a struct the caller didn't intend to share.

If you do want a function to modify the original struct, pass a pointer to it instead (func displayProduct(p *Product), called as displayProduct(&p1)) — a technique covered once pointers are introduced later in this series.

Where Structs Lead Next

Structs become significantly more powerful once you attach methods to them — functions associated with a specific struct type, which is how Go achieves the encapsulation and behavior-grouping that other languages get from classes. Structs also combine naturally with interfaces to support polymorphism without inheritance. Both topics build directly on the struct fundamentals covered here.

0 Comments

Reviewed before they appear

No comments yet.

Go
Ask about this post
AI Ask about this post

Ask questions about Go Structs and get answers drawn from it.

Signed-in readers only.