Skip to content

Go Structures

While arrays and slices in Go hold elements of the same type, structs (structures) are user-defined types that allow you to group together related data items of potentially different types into a single unit.

Structs are incredibly useful for modeling real-world entities or records. For example, if you wanted to represent information about a book, you might group attributes like title, author, subject, and ID together:

  • Title (string)
  • Author (string)
  • Subject (string)
  • BookID (int)

You define a struct using the type and struct keywords. The type keyword introduces a new type name, and struct specifies that this type is composed of a sequence of named fields, each with a type.

// Define a new struct type named 'Book'
type Book struct {
Title string // Field 'Title' of type string
Author string // Field 'Author' of type string
Subject string // Field 'Subject' of type string
BookID int // Field 'BookID' of type int
}

Once defined, Book acts as a new type. You can declare variables of this type.

Creating Instances (Variables) of a Struct

Section titled “Creating Instances (Variables) of a Struct”

There are several ways to create instances (variables) of a struct type:

// 1. Using the 'var' keyword (fields get zero values)
var book1 Book // book1.Title="", book1.Author="", ..., book1.BookID=0
// 2. Using short variable declaration with a struct literal (recommended)
book2 := Book{
Title: "Go Programming",
Author: "TutorialsPoint",
Subject: "Go Programming Tutorial",
BookID: 6495407,
}
// 3. Struct literal without field names (order must match definition - less readable, avoid)
book3 := Book{"Telecom Billing", "Zara Ali", "Telecom Billing Tutorial", 6495700}
// 4. Using 'new' built-in function (returns a pointer to a zero-valued struct)
bookPtr := new(Book) // bookPtr is of type *Book, pointing to a zero-valued Book

You access the fields (members) of a struct instance using the dot (.) operator.

package main
import "fmt"
type Book struct {
Title string
Author string
Subject string
BookID int
}
func main() {
// Create instances using struct literals
book1 := Book{
Title: "Go Programming",
Author: "TutorialsPoint",
Subject: "Go Programming Tutorial",
BookID: 6495407,
}
book2 := Book{"Telecom Billing", "Zara Ali", "Telecom Billing Tutorial", 6495700}
// Access and print Book1 fields
fmt.Printf("Book 1 Title: %s\n", book1.Title)
fmt.Printf("Book 1 Author: %s\n", book1.Author)
fmt.Printf("Book 1 Subject: %s\n", book1.Subject)
fmt.Printf("Book 1 BookID: %d\n", book1.BookID)
fmt.Println("---")
// Access and print Book2 fields
fmt.Printf("Book 2 Title: %s\n", book2.Title)
fmt.Printf("Book 2 Author: %s\n", book2.Author)
fmt.Printf("Book 2 Subject: %s\n", book2.Subject)
fmt.Printf("Book 2 BookID: %d\n", book2.BookID)
// Modify a field
book1.Author = "Updated Author"
fmt.Printf("\nBook 1 Updated Author: %s\n", book1.Author)
}

Output:

Book 1 Title: Go Programming
Book 1 Author: TutorialsPoint
Book 1 Subject: Go Programming Tutorial
Book 1 BookID: 6495407
---
Book 2 Title: Telecom Billing
Book 2 Author: Zara Ali
Book 2 Subject: Telecom Billing Tutorial
Book 2 BookID: 6495700
Book 1 Updated Author: Updated Author

You can pass structs to functions just like any other type. By default, Go passes arguments by value, meaning the function receives a copy of the struct. Modifications inside the function do not affect the original struct.

package main
import "fmt"
type Book struct {
Title string
Author string
Subject string
BookID int
}
// Function accepts a Book (by value - receives a copy)
func printBookInfo(b Book) {
fmt.Printf("Title: %s, Author: %s, ID: %d\n", b.Title, b.Author, b.BookID)
// Modifying 'b' here would only change the copy
b.Title = "Changed inside function"
}
func main() {
book1 := Book{
Title: "Go Programming",
Author: "TutorialsPoint",
Subject: "Go Programming Tutorial",
BookID: 6495407,
}
fmt.Println("Printing Book 1:")
printBookInfo(book1) // Pass a copy of book1
fmt.Printf("Original Book 1 Title after function call: %s\n", book1.Title)
}

Output:

Printing Book 1:
Title: Go Programming, Author: TutorialsPoint, ID: 6495407
Original Book 1 Title after function call: Go Programming

If you need a function to modify the original struct, or if you want to avoid copying a large struct for performance reasons, you should pass a pointer to the struct.

You declare a pointer to a struct using *TypeName (e.g., *Book). You get the address of a struct instance using the & operator.

var bookPtr *Book // Declare a pointer to a Book
book1 := Book{ ... }
bookPtr = &book1 // Assign the address of book1 to bookPtr

Go provides a convenient shorthand: you can access fields of a struct through a pointer using the same dot (.) notation as with a struct value. Go automatically dereferences the pointer for you.

bookPtr.Title
// Instead of (*bookPtr).Title, you can just write:

Example using pointers:

package main
import "fmt"
type Book struct {
Title string
Author string
Subject string
BookID int
}
// Function accepts a pointer to a Book (*Book)
func updateBookTitle(b *Book, newTitle string) {
if b == nil { // Good practice to check for nil pointers
fmt.Println("Cannot update a nil book pointer")
return
}
// Modify the Title field of the original struct via the pointer
b.Title = newTitle // Go automatically handles (*b).Title
}
func main() {
book1 := Book{
Title: "Go Programming",
Author: "TutorialsPoint",
Subject: "Go Programming Tutorial",
BookID: 6495407,
}
fmt.Printf("Original Title: %s\n", book1.Title)
// Pass the address (&) of book1 to the function
updateBookTitle(&book1, "Learning Go Structs")
fmt.Printf("Updated Title: %s\n", book1.Title)
// Example with new()
bookPtr := new(Book) // Creates a zero-valued Book and returns a pointer *Book
updateBookTitle(bookPtr, "Pointer Example")
fmt.Printf("Title from new() pointer: %s\n", bookPtr.Title)
}

Output:

Original Title: Go Programming
Updated Title: Learning Go Structs
Title from new() pointer: Pointer Example