Chapter 42: Create/Call Function
Create/Call Function” in Go (or in almost any beginner tutorial), they want to understand two things at once:
- How to create (define / declare / write) a function
- How to call (invoke / use / execute) a function
These are the two sides of the same coin — you can’t really use functions without mastering both.
Let me explain everything like your personal Go teacher sitting next to you with laptop open — slowly, clearly, with many copy-paste examples, style notes, common patterns, mistakes to avoid, and real-world usage.
1. Creating (Defining) a Function – The Syntax
The most basic form:
|
0 1 2 3 4 5 6 7 8 9 |
func functionName(parameter1 type1, parameter2 type2) returnType { // body – your code here return someValue } |
Key parts explained:
- func keyword (always first)
- functionName → starts with uppercase → exported (public, visible from other packages) → starts with lowercase → unexported (only usable inside this package)
- Parameters: name first, type after (opposite of C++/Java)
- Return type(s): after the parameter list
- Multiple return values are very common (especially value, error)
- Braces {} are mandatory (even for one line)
2. Calling (Invoking / Using) a Function
You call a function by writing its name + parentheses + arguments in the correct order.
|
0 1 2 3 4 5 6 |
result := functionName(arg1, arg2) |
If it has multiple returns:
|
0 1 2 3 4 5 6 |
value, err := functionName(arg1, arg2) |
3. Step-by-Step Examples – Let’s Build Them Together
Create a file functions.go and let’s add functions one by one.
Example 1 – No parameters, no return (void-like)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
func greet() { fmt.Println("Namaste from Hyderabad! 🇮🇳") } func main() { greet() // ← call it greet() // can call multiple times } |
Example 2 – Parameters + single return
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
func add(a int, b int) int { return a + b } func main() { sum := add(17, 25) // ← call with two arguments fmt.Println("17 + 25 =", sum) // 42 // You can call it directly in expressions fmt.Println("100 + 200 =", add(100, 200)) } |
Short parameter syntax when types are the same:
|
0 1 2 3 4 5 6 7 8 |
func multiply(x, y int) int { // x int, y int return x * y } |
Example 3 – Multiple return values (the Go classic)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
func divide(a, b float64) (float64, error) { if b == 0 { return 0, fmt.Errorf("division by zero is not allowed") } return a / b, nil // nil = no error } func main() { result, err := divide(100, 8) if err != nil { fmt.Println("Error:", err) } else { fmt.Printf("100 / 8 = %.2f\n", result) // 12.50 } // bad case _, err = divide(100, 0) fmt.Println("Bad division →", err) // prints error } |
Very important pattern: Most Go functions that can fail return (value, error) — check err != nil immediately.
Example 4 – Named return values (powerful & idiomatic)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
func splitSum(sum int) (x, y int) { x = sum * 4 / 9 y = sum - x return // naked return → returns the named x and y } func main() { a, b := splitSum(17) fmt.Println("Split 17 →", a, b) // 7 10 } |
Named returns are auto-initialized to zero value — very useful when you have early returns.
Example 5 – Variadic function (accepts variable number of arguments)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
func sumAll(numbers ...int) int { total := 0 for _, n := range numbers { total += n } return total } func main() { fmt.Println(sumAll(1, 2, 3)) // 6 fmt.Println(sumAll(10, 20, 30, 40)) // 100 fmt.Println(sumAll()) // 0 – empty // pass existing slice with ... vals := []int{5, 15, 25} fmt.Println(sumAll(vals...)) // 45 } |
Rule: only one variadic parameter and it must be the last one.
6. Common Patterns You Will Use Every Day
Pattern 1: Error-returning functions
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
func readConfig(path string) (string, error) { data, err := os.ReadFile(path) if err != nil { return "", err } return string(data), nil } |
Pattern 2: Helper functions
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
func isEven(n int) bool { return n%2 == 0 } if isEven(age) { fmt.Println("Even age") } |
Pattern 3: Functions returning functions (closures)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
func multiplier(factor int) func(int) int { return func(n int) int { return n * factor } } double := multiplier(2) triple := multiplier(3) fmt.Println(double(7)) // 14 fmt.Println(triple(7)) // 21 |
7. Style & Best Practices (2025–2026 community standard)
- Keep functions short (< 30–40 lines ideal)
- One function = one clear responsibility
- Use descriptive names (especially exported ones)
- Return early on errors
- Prefer multiple return values over panic / exceptions
- Use named returns when there are 2+ return values
- Pass slices/maps by value (cheap header copy)
- Use pointers only when you need to modify or avoid large copy
8. Quick Practice – Try Writing These
- Function greetUser(name string, age int) that prints a personalized greeting
- Function max(a, b int) int that returns the larger number
- Function getArea(length, width float64) (area float64, err error)
- Variadic function joinStrings(sep string, parts …string) string
Which one was easiest / most fun to write?
Any part still confusing?
- Why multiple returns instead of exceptions?
- Difference between named vs unnamed returns?
- When to use closures / functions as values?
- Or ready for structs or methods next?
Keep writing and calling small functions — once you feel comfortable creating and using them, you’ll be able to build real, useful programs very quickly.
You’re progressing beautifully — keep asking! 💪🇮🇳🚀
