Classes to Structs
Classes to Structs
Introduction
In this lesson, you'll learn about classes to structs 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 classes to structs.
Go has its own approach to classes to structs, 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
}
func (p Person) Greet() string {
return fmt.Sprintf("Hi, I'm %s", p.Name)
}
func main() {
p := Person{Name: "Alice", Age: 30}
fmt.Println(p.Greet())
}Comparing to C#
Here's how you might have written similar code in C#:
class Person {
public string Name { get; set; }
public int Age { get; set; }
public Person(string name, int age) {
Name = name;
Age = age;
}
public string Greet() =>
$"Hi, I'm {Name}";
}
var p = new Person("Alice", 30);
Console.WriteLine(p.Greet());You may be used to different syntax or behavior.
Go has no class keyword — use struct for data and attach methods separately
You may be used to different syntax or behavior.
Methods are defined outside the struct with a receiver: func (p Person) Method()
You may be used to different syntax or behavior.
No constructors — use struct literal or a 'New' factory function by convention
You may be used to different syntax or behavior.
No inheritance in Go — use embedding for composition
You may be used to different syntax or behavior.
All fields in a struct are zero-initialized — no constructor required for defaults
Step-by-Step Breakdown
1. Struct Definition
Go structs define data fields. They look like C# auto-property classes but have no methods inside them.
class Rectangle {
public double Width { get; set; }
public double Height { get; set; }
}type Rectangle struct {
Width float64
Height float64
}
// Initialization
r1 := Rectangle{Width: 10, Height: 5}
r2 := Rectangle{10, 5} // positional (avoid — fragile)
var r3 Rectangle // zero value: {0, 0}2. Methods with Receivers
Go methods are functions with a receiver — a named parameter that comes before the method name. The receiver can be a value or pointer.
class Rectangle {
public double Area() => Width * Height;
public void Scale(double factor) { Width *= factor; }
}// Value receiver — does not modify original
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// Pointer receiver — can modify original
func (r *Rectangle) Scale(factor float64) {
r.Width *= factor
r.Height *= factor
}3. Factory Functions Instead of Constructors
Go has no constructors. Convention is to write a NewTypeName() function that returns an initialized struct or pointer.
public Person(string name, int age) {
if (age < 0) throw new ArgumentException("age");
Name = name; Age = age;
}func NewPerson(name string, age int) (*Person, error) {
if age < 0 {
return nil, fmt.Errorf("age cannot be negative: %d", age)
}
return &Person{Name: name, Age: age}, nil
}
// Usage
p, err := NewPerson("Alice", 30)
if err != nil {
log.Fatal(err)
}4. Embedding Instead of Inheritance
Go has no inheritance. Use embedding to compose types — the embedded type's methods are promoted to the outer type.
class Employee : Person {
public string Department { get; set; }
}
// Employee inherits Greet(), Name, Agetype Employee struct {
Person // embedded — promotes Name, Age, Greet()
Department string
}
e := Employee{
Person: Person{Name: "Alice", Age: 30},
Department: "Engineering",
}
fmt.Println(e.Greet()) // promoted from Person
fmt.Println(e.Name) // promoted fieldCommon Mistakes
When coming from C#, developers often make these mistakes:
- Go has no class keyword — use struct for data and attach methods separately
- Methods are defined outside the struct with a receiver: func (p Person) Method()
- No constructors — use struct literal or a 'New' factory function by convention
Key Takeaways
- No class — use struct for data, add methods with receivers separately
- Pointer receivers (*T) for mutation; value receivers for reads
- Use NewTypeName() factory functions instead of constructors
- Embedding promotes fields/methods for composition — not inheritance