
Functions in Real-World Golang
Functions are one of the core building blocks of every Golang backend.
In real-world projects, functions are used everywhere: handlers, services, repositories, utilities, and background jobs.
This part will help you master:
- Function declaration
- Input parameters
- Multiple return values
- Error handling
- Variadic functions
- Named returns
- Higher-order functions
- Real-world backend examples
1. Function Declaration
func add(a int, b int) int {
return a + b
}
You can shorten parameters with the same type:
func add(a, b int) int {
return a + b
}
2. Multiple Return Values (Very Common in Backend)
Golang supports multiple return values — extremely useful for error handling.
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("cannot divide by zero")
}
return a / b, nil
}
Usage:
result, err := divide(10, 2)
if err != nil {
log.Println(err)
}
3. Error Handling Pattern (Idiomatic Go)
Golang does not use exceptions.
Instead, functions return errors explicitly:
func findUser(id int) (*User, error) {
user, err := db.FindByID(id)
if err != nil {
return nil, err
}
return user, nil
}
Standard pattern:
if err != nil {
return ..., err
}
This is exactly how real services & repositories are written.
4. Variadic Functions
Functions that accept unlimited parameters:
func sum(nums ...int) int {
total := 0
for _, v := range nums {
total += v
}
return total
}
Usage:
total := sum(1, 2, 3, 4)
5. Named Return Values
Sometimes useful for service functions and utilities.
func compute(a, b int) (result int) {
result = a + b
return
}
However, use this carefully:
✔ Clean for small utilities
✖ Avoid for complex functions (readability issue)
6. Functions as Values (Higher-Order Functions)
You can pass functions around:
func apply(x int, fn func(int) int) int {
return fn(x)
}
Usage:
square := func(n int) int { return n * n }
println(apply(5, square)) // Output: 25
This is powerful for middleware, callbacks, and reusable logic.
7. Real-World Example: Service Layer Function
This is how a typical service function looks in a clean-architecture Golang backend:
func (s *UserService) CreateUser(input CreateUserDTO) (*User, error) {
if input.Email == "" {
return nil, fmt.Errorf("email is required")
}
user := User{
Name: input.Name,
Email: input.Email,
}
savedUser, err := s.repo.Create(user)
if err != nil {
return nil, err
}
return savedUser, nil
}
Patterns used here:
- Input parameters (
input) - Multiple return (
*User,error) - Validation logic
- Service → repository call
- Error propagation
8. Real-World Example: Handler Function
Handlers are also regular functions:
func (h *UserHandler) CreateUser(c *gin.Context) {
var dto CreateUserDTO
if err := c.ShouldBindJSON(&dto); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
user, err := h.service.CreateUser(dto)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, user)
}
Demonstrates:
- Parameter binding
- Calling service functions
- Error handling
- JSON response
🎯 Summary
In this part, you learned:
✔ Function declaration
✔ Parameters & return types
✔ Multiple return values
✔ Real-world error handling
✔ Variadic functions
✔ Named returns
✔ Higher-order functions
✔ Service & handler examples
