Structs & Methods
Defining data types and associated behavior
Introduction
In this lesson, you'll learn about structs & methods in Go. Coming from C, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.
In C, you're familiar with defining data types and associated behavior.
Go has its own approach to defining data types and associated behavior, which we'll explore step by step.
The Go Way
Let's see how Go handles this concept. Here's a typical example:
package main
import "fmt"
type Person struct {
Name string
Age int
}
// Value receiver — read-only
func (p Person) Greet() string {
return "Hi, I'm " + p.Name
}
// Pointer receiver — mutation
func (p *Person) Birthday() {
p.Age++
}
func main() {
p := Person{Name: "Alice", Age: 30}
fmt.Println(p.Greet())
p.Birthday()
fmt.Printf("Now %d\n", p.Age)
}Comparing to C
Here's how you might have written similar code in C:
#include <stdio.h>
#include <string.h>
typedef struct {
char name[50];
int age;
} Person;
/* Functions on structs */
void person_greet(const Person *p) {
printf("Hi, I'm %s\n", p->name);
}
void person_birthday(Person *p) {
p->age++;
}
int main() {
Person p;
strncpy(p.name, "Alice", sizeof(p.name));
p.age = 30;
person_greet(&p);
person_birthday(&p);
printf("Now %d\n", p.age);
}You may be used to different syntax or behavior.
Go methods attach to struct via receiver syntax; C uses separate functions with pointer arg
You may be used to different syntax or behavior.
Go value receiver (p Person) = C's const Person*; pointer receiver (p *Person) = Person*
You may be used to different syntax or behavior.
Go uses p.Method() not p->method(); Go auto-dereferences pointers
You may be used to different syntax or behavior.
Go struct literals use field names; C requires member-by-member or designated initializers
Step-by-Step Breakdown
1. Receiver Methods
Go attaches functions to a type using a receiver, similar to C's pattern of passing a struct pointer as the first argument.
void person_greet(const Person *p) { ... }func (p Person) Greet() string { ... }2. Pointer vs Value Receiver
Use a pointer receiver (*T) when the method must modify the struct — equivalent to C's non-const pointer parameter.
void person_birthday(Person *p) { p->age++; }func (p *Person) Birthday() { p.Age++ }3. Struct Literals
Go struct literals are cleaner than C's member-by-member initialization.
Person p; strncpy(p.name, "Alice", 50); p.age = 30;p := Person{Name: "Alice", Age: 30}Common Mistakes
When coming from C, developers often make these mistakes:
- Go methods attach to struct via receiver syntax; C uses separate functions with pointer arg
- Go value receiver (p Person) = C's const Person*; pointer receiver (p *Person) = Person*
- Go uses p.Method() not p->method(); Go auto-dereferences pointers
Key Takeaways
- Go receiver methods replace C's struct-pointer function pattern
- Value receiver = const pointer; pointer receiver = mutable pointer
- Go auto-dereferences — use p.Field not p->Field
- Struct literals are concise in Go