Functions & Methods
Functions in Go Language
In Go, functions are segments of code designed to carry out specific tasks. They can be reused throughout the program to optimize memory usage, enhance code clarity, and save time. Functions may return a value to the caller or not, depending on their implementation.
Syntax:
func function_name(Parameter-list)(Return_type) {
// function body...
}
Example:
package main
import "fmt"
// add() takes two integers and returns their sum
func add(x, y int) int {
return x + y
}
func main() {
sum := add(8, 12)
fmt.Printf("Sum: %d", sum)
}
Output:
Sum: 20
Function Declaration
In Go, functions are defined using the func
keyword, followed by the function name, a parameter list, and an optional return type.
Syntax:
func function_name(Parameter-list)(Return_type) {
// function body...
}
Example:
func add(x, y int) int {
return x + y
}
Output:
marks are 500 or more
Explanation:
- func: Used to declare a function.
- function_name: The name of the function, e.g.,
add
. - Parameter-list:
x, y int
are the parameters with their types. - Return_type:
int
specifies the return type.
Function Calling
To execute a function, use its name followed by any required arguments in parentheses. For instance, add(8, 12)
invokes the function with the arguments 8 and 12.
Example:
sum := add(8, 12)
fmt.Printf("The sum is: %d", sum)
Output:
// Go program to demonstrate
// the use of nested if statements
package main
import "fmt"
func main() {
// Declare two variables
var a int = 250
var b int = 500
// Check the first condition
if a < 300 {
// If condition1 is true,
// check the nested condition
if b < 600 {
// Executes if both conditions are true
fmt.Printf("a is less than 300 and b is less than 600\n")
}
}
}
Function Arguments
Go allows two methods for passing arguments to functions: Call by Value and Call by Reference. By default, Go employs call by value, where argument values are copied, ensuring that modifications inside the function do not affect the original variables.
1. Call by Value: In this approach, the argument values are passed as copies to the function. Any changes made to these values inside the function remain local to the function.
Example:
package main
import "fmt"
func add(x, y int) int {
x = x + 5 // modifying x within the function
return x + y
}
func main() {
a := 10
b := 20
fmt.Printf("Before: a = %d, b = %d\n", a, b)
total := add(a, b)
fmt.Printf("Sum: %d\n", total)
fmt.Printf("After: a = %d, b = %d\n", a, b)
}
Output:
Before: a = 10, b = 20
Sum: 35
After: a = 10, b = 20
2. Call by Reference: In this method, pointers are passed to the function, allowing modifications made inside the function to affect the original variables.
Example:
package main
import "fmt"
func add(x, y *int) int {
*x = *x + 5 // modifying x via its memory address
return *x + *y
}
func main() {
a := 10
b := 20
fmt.Printf("Before: a = %d, b = %d\n", a, b)
total := add(&a, &b)
fmt.Printf("Sum: %d\n", total)
fmt.Printf("After: a = %d, b = %d\n", a, b)
}
Output:
value is 150
Variadic functions in Go
Variadic functions in Go allow you to pass a flexible number of arguments to a function. This capability is particularly helpful when the exact number of arguments is unknown beforehand. A variadic function accepts multiple arguments of the same type and can handle calls with any number of arguments, including none.
Syntax:
func functionName(parameters ...Type) ReturnType {
// Code
}
Example:
package main
import "fmt"
// Variadic function to calculate product
func product(nums ...int) int {
result := 1
for _, n := range nums {
result *= n
}
return result
}
func main() {
fmt.Println("Product of 2, 3, 4:", product(2, 3, 4))
fmt.Println("Product of 6, 7:", product(6, 7))
fmt.Println("Product with no numbers:", product())
}
Output:
Product of 2, 3, 4: 24
Product of 6, 7: 42
Product with no numbers: 1
In the syntax above:
parameters ...Type
denotes that the function can accept a flexible number of arguments of typeType
.- Inside the function, these arguments are accessible as a slice.
Using Variadic Functions
When defining a variadic function, include the ellipsis (...
) after the parameter name, followed by the type of the arguments. These arguments are processed as a slice within the function.
Calling a Variadic Function
A variadic function can be called with any number of arguments, even none. The arguments provided are handled as a slice.
Example:
package main
import "fmt"
func product(nums ...int) int {
result := 1
for _, n := range nums {
result *= n
}
return result
}
func main() {
fmt.Println("Product of 1, 2, 3:", product(1, 2, 3))
fmt.Println("Product of 5, 10:", product(5, 10))
fmt.Println("Product with no numbers:", product())
}
Output:
Product of 1, 2, 3: 6
Product of 5, 10: 50
Product with no numbers: 1
Combining Variadic Functions with Regular Parameters
You can mix regular parameters with a variadic parameter in a single function. However, the variadic parameter must always come last in the parameter list.
Example:
package main
import "fmt"
// Function with both a regular parameter and a variadic parameter
func displayMessage(message string, numbers ...int) {
fmt.Println(message)
for _, n := range numbers {
fmt.Println("Value:", n)
}
}
func main() {
displayMessage("Values are:", 7, 8, 9)
displayMessage("More values:", 15, 20)
displayMessage("No values provided:")
}
Output:
Values are:
Value: 7
Value: 8
Value: 9
More values:
Value: 15
Value: 20
No values provided:
Anonymous function in Go Language
An anonymous function is a function that lacks a name. It is particularly useful when you need to create a function inline. In Go, anonymous functions can also form closures. These are also referred to as function literals.
Syntax:
func(parameter_list)(return_type) {
// Code block
// Use return statement if return_type is provided.
// If return_type is absent, do not use the return statement.
return
}()
Example:
package main
import "fmt"
func main() {
// Anonymous function
func() {
fmt.Println("Hello, World from Go!")
}()
}
Output:
Hello, World from Go!
Assigning to a Variable
Anonymous functions can be assigned to a variable. Once assigned, the variable behaves like a regular function and can be invoked.
Syntax:
for {
// statements...
}
Example:
// Go program demonstrating a for loop as a while loop
package main
import "fmt"
func main() {
x := 0
for x < 4 {
fmt.Println("Value of x:", x)
x++
}
}
Output:
Value of x: 0
Value of x: 1
Value of x: 2
Value of x: 3
Passing Arguments
Anonymous functions are capable of accepting arguments.
Example:
package main
import "fmt"
func main() {
// Passing arguments in an anonymous function
func(greeting string) {
fmt.Println(greeting)
}("Hello, Go Developers!")
}
Output:
Hello, Go Developers!
Passing as Arguments
It is also possible to pass an anonymous function as an argument to another function.
Example:
package main
import "fmt"
// Passing an anonymous function as an argument
func processStrings(fn func(a, b string) string) {
fmt.Println(fn("Hello ", "Go "))
}
func main() {
combine := func(a, b string) string {
return a + b + "Developers!"
}
processStrings(combine)
}
Output:
Hello Go Developers!
Returning Anonymous Functions
An anonymous function can also be returned from another function, allowing you to use it later.
Example:
package main
import "fmt"
// Function returning an anonymous function
func createGreeting() func(first, second string) string {
return func(first, second string) string {
return first + second + "is awesome!"
}
}
func main() {
greet := createGreeting()
fmt.Println(greet("Go ", "Language "))
}
Output:
Go Language is awesome!
The Go language reserves two functions for special purposes: main()
and init()
.
main()
Function
In Go, the main
package is a unique package used with programs that are designed to be executable. This package contains the main()
function, which is a crucial function that serves as the entry point of all executable programs. The main()
function neither accepts any arguments nor returns a value. It is automatically invoked by the Go runtime, so there is no need to explicitly call it. Every executable program must include exactly one main
package and one main()
function.
Example:
// Go program demonstrating the
// functionality of main() function
// Defining the main package
package main
// Importing necessary packages
import (
"fmt"
"math"
"strings"
"time"
)
// Main function
func main() {
// Performing square root operation
numbers := []float64{16, 25, 36, 49, 64}
for _, num := range numbers {
fmt.Printf("Square root of %.0f: %.2f\n", num, math.Sqrt(num))
}
// Finding the substring index
fmt.Println("Index of substring:", strings.Index("HelloWorld", "World"))
// Displaying the current timestamp
fmt.Println("Current Unix time:", time.Now().Unix())
}
Output:
Square root of 16: 4.00
Square root of 25: 5.00
Square root of 36: 6.00
Square root of 49: 7.00
Square root of 64: 8.00
Index of substring: 5
Current Unix time: 1737138000
init()
Function
The init()
function in Go is another special function that, like main()
, neither accepts arguments nor returns values. It exists in every package and is automatically invoked when the package is initialized. This function is implicitly declared and cannot be explicitly called or referenced from other parts of the program. Multiple init()
functions can be defined within the same program, and they execute in the order they are declared. The execution order of init()
functions across multiple files follows the lexical order of the filenames (alphabetical order). The primary purpose of the init()
function is to initialize global variables or perform setup tasks that cannot be accomplished in the global scope.
Example:
// Go program demonstrating the
// behavior of init() function
// Defining the main package
package main
// Importing required package
import "fmt"
// Defining the first init() function
func init() {
fmt.Println("First init() function executed")
}
// Defining the second init() function
func init() {
fmt.Println("Second init() function executed")
}
// Main function
func main() {
fmt.Println("main() function executed")
}
Output:
First init() function executed
Second init() function executed
main() function executed
Defer Keyword in Golang
In the Go programming language, defer
statements postpone the execution of a function, method, or anonymous function until the surrounding function completes. In simpler terms, while the arguments of a deferred function or method call are evaluated immediately, the execution itself is deferred until the enclosing function returns. You can define a deferred function, method, or anonymous function by using the defer
keyword.
Syntax:
// For a function
defer func func_name(parameter_list Type) return_type {
// Code
}
// For a method
defer func (receiver Type) method_name(parameter_list) {
// Code
}
// For an anonymous function
defer func(parameter_list) (return_type) {
// Code
}()
Key Points:
- The Go language allows multiple
defer
statements in the same program, and they execute in LIFO (Last-In, First-Out) order, as illustrated in Example 2. - The arguments of
defer
statements are evaluated immediately when the statement is encountered, but the function itself executes only when the surrounding function returns. Defer
statements are commonly used for tasks like closing files, closing channels, or handling program panics gracefully.
Example:
// Go program demonstrating the concept of defer statements
package main
import "fmt"
// Function to calculate the difference
func difference(a1, a2 int) int {
res := a1 - a2
fmt.Println("Difference:", res)
return 0
}
// Function to display a message
func greet() {
fmt.Println("Welcome to Go programming!")
}
// Main function
func main() {
// Normal call to difference() function
difference(100, 40)
// Deferred call to difference() function
defer difference(200, 50)
// Calling greet() function
greet()
}
Output:
Difference: 60
Welcome to Go programming!
Difference: 150
Methods in Golang
Go methods are similar to functions but with a significant difference: they have a receiver argument that allows access to the receiver’s properties. The receiver can either be a struct type or a non-struct type, but both must be part of the same package. You cannot define methods for types from other packages or for built-in types like int
or string
, as the compiler will generate an error.
Syntax:
func (receiver_name Type) method_name(parameter_list) (return_type) {
// Method implementation
}
Example:
package main
import "fmt"
// Defining a struct
type car struct {
brand string
year int
}
// Defining a method with a struct receiver
func (c car) details() {
fmt.Println("Brand:", c.brand)
fmt.Println("Year:", c.year)
}
func main() {
// Creating an instance of the struct
vehicle := car{brand: "Toyota", year: 2022}
// Calling the method
vehicle.details()
}
Output:
Brand: Toyota
Year: 2022
Methods with Struct Type Receiver
When defining a method, the receiver can be a struct type. The receiver is accessible within the method. The earlier example demonstrates this with a struct type receiver.
Methods with Non-Struct Type Receiver
Go supports defining methods with non-struct type receivers, provided the type and the method definition exist in the same package. However, you cannot define methods for types from another package (e.g., int
, string
).
Example:
package main
import "fmt"
// Creating a custom type based on float64
type measurement float64
// Defining a method with a non-struct receiver
func (m measurement) double() measurement {
return m * 2
}
func main() {
value := measurement(3.5)
result := value.double()
fmt.Printf("Double of %.1f is %.1f\n", value, result)
}
Output:
Double of 3.5 is 7.0
Methods with Pointer Receiver
In Go, methods can also have pointer receivers, enabling modifications to the original data. This capability is unavailable with value receivers.
Syntax:
func (receiver *Type) method_name(parameters...) return_type {
// Code to modify data
}
Example:
package main
import "fmt"
// Defining a struct
type animal struct {
species string
}
// Method with pointer receiver to modify data
func (a *animal) rename(newSpecies string) {
a.species = newSpecies
}
func main() {
pet := animal{species: "Cat"}
fmt.Println("Before:", pet.species)
// Calling the method to rename
pet.rename("Dog")
fmt.Println("After:", pet.species)
}
Output:
Before: Cat
After: Dog
Methods Accepting Both Pointer and Value
In Go, methods can accept both value and pointer receivers. Depending on how the method is invoked, Go automatically handles the conversion between pointers and values.
Example:
package main
import "fmt"
type book struct {
title string
}
// Method with pointer receiver
func (b *book) setTitle(newTitle string) {
b.title = newTitle
}
// Method with value receiver
func (b book) displayTitle() {
fmt.Println("Title:", b.title)
}
func main() {
novel := book{title: "Untitled"}
// Calling pointer receiver method with value
novel.setTitle("1984")
fmt.Println("After pointer method:", novel.title)
// Calling value receiver method with pointer
(&novel).displayTitle()
}
Output:
After pointer method: 1984
Title: 1984
Difference Between Method and Function
Aspect | Method | Function |
---|---|---|
Contains a receiver | Yes | No |
Allows same name with different types | Yes | No |
Usable as a first-order object | No | Yes |
Related Chapters
- Introduction of Go-Lang
- Fundamentals in Go
- Control Statement in Go
- Functions & Methods in Go
- Structures in Go
- Arrays in Go
- Slices in Go
- File Handling in I/O
- Pointers in Go
- Concurrency in Go
- Object Oriented Programming in Go
- Defer and Error Handling in Go
- First Class Functions in Go
- Reflection in Go
- File Handling in Go