Contents
First Class Functions
First-Class Functions in Go
A language that supports first-class functions allows functions to be:
- Assigned to variables.
- Passed as arguments to other functions.
- Returned from other functions.
Anonymous Functions
Anonymous functions are functions without a name, which can be assigned to variables or invoked immediately.
Example of Assigning a Function to a Variable:
package main
import (
"fmt"
)
func main() {
greet := func() {
fmt.Println("Hello from an anonymous function!")
}
greet()
fmt.Printf("Type of greet: %T", greet)
}
Output:
Hello from an anonymous function!
func()
Here, greet
holds an anonymous function that is invoked using greet()
.
Immediately Invoking an Anonymous Function
package main
import (
"fmt"
)
func main() {
func() {
fmt.Println("Hello, Go developers!")
}()
}
Output:
Hello, Go developers!
Anonymous Function with Arguments
package main
import (
"fmt"
)
func main() {
func(name string) {
fmt.Println("Welcome,", name)
}("Developers")
}
Output:
Welcome, Developers
User-Defined Function Types
You can define custom types for functions, just like structs.
type mathOp func(x, y int) int
The above creates a new type mathOp
for functions that take two int
arguments and return an int
.
Example:
package main
import (
"fmt"
)
type mathOp func(x, y int) int
func main() {
add := func(x, y int) int {
return x + y
}
var operation mathOp = add
fmt.Println("Sum:", operation(3, 7))
}
Output:
Sum: 10
Higher-Order Functions
A higher-order function:
- Accepts other functions as arguments.
- Returns a function as its result.
Let’s look at some simple examples for the above two scenarios.
Passing functions as arguments to other functions
package main
import (
"fmt"
)
func compute(op func(x, y int) int) {
fmt.Println("Result:", op(10, 5))
}
func main() {
multiply := func(x, y int) int {
return x * y
}
compute(multiply)
}
Output:
Result: 50
Returning Functions from Functions
package main
import (
"fmt"
)
func generateMultiplier(factor int) func(int) int {
return func(x int) int {
return x * factor
}
}
func main() {
double := generateMultiplier(2)
fmt.Println("Double of 8:", double(8))
}
Output:
Double of 8: 16
Closures
A closure is an anonymous function that captures and uses variables from its surrounding scope.
Example:
package main
import (
"fmt"
)
func main() {
message := "Hello"
func() {
fmt.Println(message)
}()
}
Output:
Hello
Independent Closures
package main
import (
"fmt"
)
func counter() func() int {
value := 0
return func() int {
value++
return value
}
}
func main() {
c1 := counter()
c2 := counter()
fmt.Println(c1()) // 1
fmt.Println(c1()) // 2
fmt.Println(c2()) // 1
}
Output:
1
2
1
Practical Examples of First-Class Functions
Filtering a Slice
package main
import (
"fmt"
)
type student struct {
name string
grade string
country string
}
func filter(students []student, criteria func(student) bool) []student {
var result []student
for _, s := range students {
if criteria(s) {
result = append(result, s)
}
}
return result
}
func main() {
students := []student{
{name: "Alice", grade: "A", country: "USA"},
{name: "Bob", grade: "B", country: "India"},
}
byGradeB := filter(students, func(s student) bool {
return s.grade == "B"
})
fmt.Println("Students with grade B:", byGradeB)
}
Output:
Students with grade B: [{Bob B India}]
Map Function
package main
import (
"fmt"
)
func mapInts(numbers []int, operation func(int) int) []int {
var result []int
for _, n := range numbers {
result = append(result, operation(n))
}
return result
}
func main() {
numbers := []int{2, 3, 4}
squared := mapInts(numbers, func(n int) int {
return n * n
})
fmt.Println("Squared values:", squared)
}
Output:
Squared values: [4 9 16]