Practical Struct Design
Designing Structs with Visibility in Mind
Effective struct design in Go requires careful consideration of visibility, encapsulation, and overall architectural principles.
Struct Design Patterns
graph TD
A[Struct Design Patterns] --> B[Encapsulation]
A --> C[Immutability]
A --> D[Composition]
A --> E[Interface Implementation]
Encapsulation Strategy
package user
// User represents a user in the system
type User struct {
// Unexported fields for internal state management
id int
username string
email string
}
// NewUser creates a controlled user instance
func NewUser(username, email string) (*User, error) {
// Validation logic
if len(username) < 3 {
return nil, fmt.Errorf("invalid username")
}
return &User{
username: username,
email: email,
}, nil
}
// GetUsername provides controlled access to username
func (u *User) GetUsername() string {
return u.username
}
Visibility Patterns
Pattern |
Description |
Use Case |
Constructor Methods |
Create controlled object instances |
Validation, initialization |
Getter/Setter Methods |
Provide controlled field access |
Data protection |
Composition |
Build complex types from simpler ones |
Modular design |
Advanced Struct Design Techniques
Immutable Struct Design
package config
// ImmutableConfig demonstrates an immutable configuration
type ImmutableConfig struct {
// Unexported fields prevent direct modification
host string
port int
}
// NewImmutableConfig creates a configuration instance
func NewImmutableConfig(host string, port int) *ImmutableConfig {
return &ImmutableConfig{
host: host,
port: port,
}
}
// WithHost returns a new config with updated host
func (c *ImmutableConfig) WithHost(newHost string) *ImmutableConfig {
return &ImmutableConfig{
host: newHost,
port: c.port,
}
}
Interface-Based Design
package storage
// Storage defines a generic storage interface
type Storage interface {
Save(data []byte) error
Retrieve() ([]byte, error)
}
// FileStorage implements the Storage interface
type FileStorage struct {
// Unexported fields
filePath string
}
// Implement interface methods with controlled visibility
func (fs *FileStorage) Save(data []byte) error {
// Implementation details
}
LabEx Insights
When designing structs, LabEx recommends focusing on:
- Minimal exported surface area
- Clear, purposeful method designs
- Consistent visibility patterns
Composition Over Inheritance
graph TD
A[Struct Composition] --> B[Embed Smaller Structs]
A --> C[Delegate Functionality]
A --> D[Avoid Deep Inheritance]
- Keep structs lightweight
- Use pointers for large structs
- Minimize unnecessary allocations
- Leverage interface-based designs
Error Handling and Validation
- Use constructors for input validation
- Return detailed error information
- Prevent invalid state creation
- Provide clear error messages
Best Practices Summary
- Protect internal state
- Use unexported fields
- Implement controlled access methods
- Design for composition
- Validate inputs at creation time