Department of Artificial Intelligence and Machine Learning
Lab Manual
for
Go Programming - 22AMA582
Prepared By,
Mrs. Aruna T M
Assistant Professor G-II
Department of AI&ML
NMIT, Bengaluru
Vision
To produce competent professionals in the field of AI & ML with excellent knowledge,
technical skills and righteous values contributing to the growth of society.
Mission
Empower our AI and Machine Learning community to lead with expertise and
innovation.
Position our department as a global hub for AI excellence through collaborative
research and education.
Connect academia and industry seamlessly to address real-world challenges in AI and
Machine Learning.
Cultivate a culture of continuous learning and innovation within our community.
Programme Educational objectives (PEOs):
The graduates of AI and ML program will be able to:
PEO 1:Graduates will proficiently apply AI and Machine Learning techniques to
creatively address complex challenges, showcasing advanced problem-solving skills.
PEO 2:Alumni will lead with ethical considerations, ensuring responsible AI
development and contributing positively to societal and industry standards.
PEO 3:Program completers will excel in interdisciplinary collaboration, effectively
communicating and integrating AI solutions across diverse domains.
Programme Outcomes (POs)
PO1. Engineering knowledge: Apply the knowledge of mathematics, science,
engineering fundamentals, and an engineering specialization to the solution of
complex engineering problems.
PO2. Problem analysis: Identify, formulate, review research literature, and analyze
complex engineering problems reaching substantiated conclusions using first
principles of mathematics, natural sciences, and engineering sciences.
PO3. Design/development of solutions: Design solutions for complex engineering
problems and design system components or processes that meet the specified needs
with appropriate consideration for the public health and safety, and the cultural,
societal, and environmental considerations.
PO4. Conduct investigations of complex problems: Use research-based knowledge
and research methods including design of experiments, analysis and interpretation of
data, and synthesis of the information to provide valid conclusions.
PO5. Modern tool usage: Create, select, and apply appropriate techniques, resources,
and modern engineering and IT tools including prediction and modeling to complex
engineering activities with an understanding of the limitations.
PO6.Theengineer and society:Apply reasoning informed by the contextual
knowledge to assess societal, health, safety, legal and cultural issues and the
consequent responsibilities relevant to the professional engineering practice.
PO7. Environment and sustainability:Understand the impact of the professional
engineering solutions in societal and environmental contexts, and demonstrate the
knowledge of, and need for sustainable development.
PO8.Ethics: Apply ethical principles and commit to professional ethics and
responsibilities and norms of the engineering practice.
PO9.Individual and teamwork:Function effectively as an individual, and as a
member or leader in diverse teams, and in multidisciplinary settings.
PO10. Communication:Communicate effectively on complex engineering activities
with the engineering community and with society at large, such as, being able to
comprehend and write effective reports and design documentation, make effective
presentations, and give and receive clear instructions.
PO11. Project management and finance:Demonstrate knowledge and
understanding of the engineering and management principles and apply these to one’s
own work, as a member and leader in a team, to manage projects and in
multidisciplinary environments.
PO12. Life-long learning: Recognize the need for and have the preparation and
ability to engage in independent and life-long learning in the broadest context of
technological change.
Programme Specific Outcomes (PSOs):
PSO 1: Graduates will demonstrate proficiency in designing and implementing
advanced AI and Machine Learning algorithms, showcasing the ability to develop
innovative solutions for complex real-world problems.m.
PSO 2:Program graduates will exhibit a strong foundation in interdisciplinary
collaboration, effectively applying AI and Machine Learning techniques to diverse
domains, fostering a holistic approach to technological solutions knowledge.
GO PROGRAMMING
Course Code 22AMA582 Credits 1
Hours/Week (L- 3-0 CIE Marks 50
T-P-S)
Total Teaching 26 SEE Marks 100
Hours
Exam Hours 03 Course Type AEC
COURSE LEARNING OUTCOMES
Students will be able to:
1. Implement the basic structure and syntax of a Go program.
2. Demonstrate proficiency in using Go's basic and composite data types for various
programming tasks.
3. Create and use functions in Go, including handling parameters and return values.
4. Apply methods in Go, understanding their role in the language's approach to object-oriented
programming.
5. Implement interfaces in Go, using them to design flexible and modular programs.
COURSE CONTENTS
UNIT -1- (08Hrs)
Introduction Tutorial, Program Structure, Basic data types
UNIT -2- (08 Hrs)
Decision making, loops, Pointers, Composite types
UNIT -3- (8 Hrs)
Functions in Go
UNIT -4- (08 Hrs)
Methods in Go
UNIT -5- (08 Hrs)
Go Interfaces
TEXTBOOKS
S.No UNIT TITLE AUTHOR(S) PUBLISHER(S) EDITION /
YEAR OF
PUBLICATION
1 ALL The Go Alan A. A. Paperback 1st Edition/
Programming Donovan and Publication February 2016
Language Brian W.
Kernighan
REFERENCE BOOKS
1 ALL Go Mat Ryer Packt 2nd edition/
Programming Publishing October 2016
Blueprints
2 ALL Go in Action William Manning First Edition/
Kennedy, Brian November 2015
Ketelsen, and
Erik St. Martin
ONLINE RESOURCES
Go (Golang) Tutorial Golang Tutorial for Beginners | Full Go Course
(youtube.com)
COURSE ASSESSMENT METHOD
Continuous Internal Evaluation (CIE):
Two internal Assessements-MSE1 & MSE2 (each 50 marks) are conducted.
Final MSE marks will be the average of MSE1 and MSE2, Finally scaled down to 30 marks
Quiz tests are conducted and evaluated for 10 marks.
Project/Seminar/Case Study are conducted and evaluated for 10 marks
Semester End Examination (SEE): Final examination, of 100 Marks will be conducted and will be
evaluated for 50 marks.
PEDAGOGY
Blackboard Teaching/PowerPoint presentations
Hands-on Session in Lab
LABORATORY EXERCISES
S.No LIST OF EXPERIMENTS
1. Write a Go program that calculates the factorial of a number using iterative and recursive
approaches. Ensure the program handles large numbers efficiently.
2. Implement a Go program that simulates a simple banking system. Use structs to represent
bank accounts with methods for deposit, withdrawal, and balance checking
3. Create a Go program that reads a matrix of integers from the user and checks if it forms a
symmetric matrix. Use pointers and composite types effectively.
4. Write a Go program that demonstrates the use of pointers to swap the values of two integers.
Ensure the program handles edge cases such as zero values.
5. Develop a Go program that implements a recursive function to compute the Fibonacci
sequence up to a specified number. Optimize the function for efficiency.
6. Design a Go program that models a library management system. Implement methods on a
struct representing a book to handle borrowing, returning, and availability status.
7. Extend the library management system from the previous question by implementing an
interface for library items. Ensure books and other media can be managed uniformly.
8. Create a Go program that uses interfaces to define a shape hierarchy (e.g., square, circle).
Implement methods to calculate area and perimeter for each shape and demonstrate
polymorphism
CO-PO-PSO MAPPING
PO PSO1 PSO2
CO
1 2 3 4 5 6 7 8 9 10 11 12
1 3 - - - - - - - - 1 - - - -
2 1 1 3 - 3 - - - 2 1 - - - -
3 2 3 1 - 1 - - - 2 2 - - - -
4 3 2 2 - 3 - - - 1 1 - - - -
5 2 3 2 - 1 - - - 2 2 - - - -
Step-by-Step Guide to Install Go and Setting Up Environment Variables
Step 1: Download and Install Go
1. Download Go:
Visit the Download and install - The Go Programming Language
Choose the installer that matches your operating system (Windows, macOS, or
Linux).
2. Install Go:
Run the installer and follow the installation instructions.
Once installation is complete, Go will be installed in the default directory.
Step 2: Set Up Environment Variables
Windows:
1. Open Environment Variables Settings:
Right-click on This PC (or My Computer) and select Properties.
Click on Advanced system settings on the left.
In the System Properties window, click on the Environment Variables button.
2. Add GOPATH and GOROOT:
In the User variables section, click New and add the following:
o Variable name: GOROOT
o Variable value: The installation directory of Go (e.g., C:\Go)
In the User variables section, create another variable:
o Variable name: GOPATH
o Variable value: The path where your Go projects will be stored (e.g., C:\Users\
YourName\go)
3. Update the Path Variable:
In the System variables section, find the Path variable, select it, and click Edit.
Add the following paths:
o C:\Go\bin (replace C:\Go with your Go installation path)
o %GOPATH%\bin
4. Apply Changes:
1Click OK on all the windows to save the changes.
5. Verify Installation:
Open a new Command Prompt and run the following command
6. Verify Installation:
Open a new Command Prompt(ctrl+r type “run” Enter) and run the following
command
> go version
7. You should see something like:
go version go1.x.x windows/amd64
macOS:
1. Open Terminal and install Go by downloading the macOS installer from the
Download and install - The Go Programming Language
2. Set Environment Variables in .bash_profile or .zshrc:
Open Terminal and edit your profile file:
nano ~/.bash_profile # For bash
nano ~/.zshrc # For zsh (default shell in macOS Catalina or later)
Add the following lines:
export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH
3. Apply the Changes:
Save the file and reload it:
source ~/.bash_profile # For bash
source ~/.zshrc # For zsh
4. Verify Installation:
Run the following command in Terminal:
go version
You should see the Go version installed.
Linux (Ubuntu/Debian):
1. Download the Go Binary:
Download the tarball using wget or from the Download and install - The
Go Programming Language
wget https://golang.org/dl/go1.x.x.linux-amd64.tar.gz
2. Extract and Install Go:
Extract the archive to /usr/local:
sudo tar -C /usr/local -xzf go1.x.x.linux-amd64.tar.gz
3. Set Up Environment Variables:
Open your .bashrc or .zshrc file for editing:
nano ~/.bashrc # For bash
nano ~/.zshrc # For zsh
Add the following lines:
export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH
4. Apply the Changes:
Save and reload the file:
source ~/.bashrc # For bash
source ~/.zshrc # For zsh
5. Verify Installation:
Run the following command to check the Go version:
go version
You should see the installed version of Go.
Step 3: Test Go Installation
1. Create a Go Program:
Create a directory for your Go projects (if not done during setup):
mkdir -p $GOPATH/src/hello
cd $GOPATH/src/hello
2. Write a Go Program:
Create a file hello.go and type the below program
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
3. Run the Go Program:
Compile and run the Go programin the command prompt:
go run hello.go
4. You should see in the command prompt:
Hello, World!
1) How to create a Go file on windows:
1. Open Command Prompt or PowerShell.
2. Navigate to your Go workspace:
If you followed the setup, your workspace will be in C:\Users\YourUsername\
go\src\hello.
You can navigate using the command in the command prompt:
cd C:\Users\YourUsername\go\src\hello
3. Create the hello.go file:
In Command Prompt or PowerShell, type:
notepad hello.go
This will open Notepad. Enter the following Go code in Notepad
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
4. Save and close the file.
2) How to create a Go file on macOS/Linux:
1. Open Terminal.
2. Navigate to your Go workspace:
Assuming your Go workspace is in ~/go/src/hello, navigate there using:
cd ~/go/src/hello
3. Create the hello.go file:
Use the nano text editor (or any other text editor like vim or gedit):
nano hello.go
In the editor, type the following Go code
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
4. Save the file:
For nano, press Ctrl + O, then Enter to save.
Press Ctrl + X to exit the editor.
3) Running the Go Program:
1. Go to the directory where you created the hello.go file.
2. Run the program using:
go run hello.go
3. You should see the following output:
Hello, World!
- - -That's it! You've successfully created and run your Go program. - - -
UNIT -1- (08Hrs)
1.1 Introduction Tutorial:
Go, often referred to as Golang, is a modern, statically typed, compiled programming
language developed by Google in 2007.
It was designed by Robert Griesemer, Rob Pike, and Ken Thompson with the aim of
addressing some of the issues developers face in large-scale software development.
1.1.1 Why Go Was Developed?
Go was created to improve upon some of the shortcomings of older languages like C and
C++. It was designed to:
Improve productivity by simplifying complex language features.
Enhance compilation speed—Go compiles quickly even for large programs.
Provide native support for concurrency, a necessity for modern software that often
runs in distributed environments.
Improve memory management with built-in garbage collection.
Make deployment easier by producing statically compiled binaries, which contain
everything needed to run the program, avoiding dependency issues.
1.1.2 Key Features of Go
Statically Typed and Compiled: Go checks types at compile time, ensuring safer,
faster code execution by compiling directly into machine code.
Simplicity and Clarity: Go's design avoids complexity like inheritance and function
overloading, making code cleaner and easier to read.
Concurrency Support: Go provides lightweight threads (goroutines) for efficient,
easy-to-manage concurrent programming.
Garbage Collection: Go automatically manages memory with garbage collection,
preventing memory leaks and manual memory handling.
Cross-Platform: Go code can run on different operating systems without
modification, producing self-contained binaries.
Efficient Standard Library: Go offers a robust standard library for tasks like
networking, file handling, and web servers, reducing dependency on external libraries.
1.1.3 Go’s Popular Use Cases
Web Servers and APIs: Go's concurrency and simplicity make it perfect for building
high-performance web servers and APIs like Docker and Kubernetes.
Microservices: Go’s fast execution and minimalistic design are ideal for developing
lightweight, maintainable microservices.
Cloud-Native Applications: Go excels in cloud environments with its concurrency
model, used in systems like Kubernetes and Prometheus.
Networking Tools: Go’s strong networking capabilities power high-performance
tools like Caddy and Traefik.
1.2 Basic Syntax and Structure of a Go Program
Go’s syntax is simple and clean, resembling C but avoiding many of the
complexities.
Here is a basic "Hello, World!" program in Go:
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
Where,
o Package Declaration (package main): Every Go program is made up of packages,
and the main package is the starting point of execution.
o Imports (import "fmt"): Go uses the import statement to include other packages. In
this case, the fmt package is used for formatted I/O operations.
o Functions (func main()): The main function is the entry point of the Go program.
Every executable program must have a main function.
Important Note:
Must-Have: package main and func main ().
Optional: Import statements, additional functions, variables, control structures,
composite types, and concurrency elements.
1.2.1 Is Go Programming Case-Sensitive?
o Yes, Go is case-sensitive.
o This means that identifiers such as variable names, function names, and type names
must match exactly in case.
o For example, myVar and MyVar would be treated as two different identifiers in Go.
Here’s an example:
package main // Must have component
import "fmt"
func main() { // Must have component
var myVar int = 10
var MyVar int = 20
fmt.Println(myVar) // Outputs 10
fmt.Println(MyVar) // Outputs 20
1.3 Basic Data Types in Go
1. Integers:
o Signed: int, int8, int16, int32, int64
o Unsigned: uint, uint8, uint16, uint32, uint64
2. Floating-Point Numbers:
o float32, float64
3. Boolean:
o bool
4. String:
o string
5. Complex Numbers:
o complex64, complex128
6. Rune (alias for int32):
o Represents a Unicode character.
7. Byte (alias for uint8):
o Represents binary data or ASCII characters.
1.3.1 Integer Types
Go supports both signed and unsigned integer types.
Signed Integers:
int: The default integer type (size depends on the system architecture, either 32 or 64
bits).
int8: Range from -128 to 127.
int16: Range from -32,768 to 32,767.
int32: Range from -2,147,483,648 to 2,147,483,647.
int64: Range from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807.
Unsigned Integers:
uint: Default unsigned integer type (either 32 or 64 bits).
uint8: Range from 0 to 255.
uint16: Range from 0 to 65,535.
uint32: Range from 0 to 4,294,967,295.
uint64: Range from 0 to 18,446,744,073,709,551,615.
Example:
package main
import "fmt"
func main() {
var a int8 = -128 // Signed 8-bit integer
var b uint8 = 255 // Unsigned 8-bit integer
fmt.Println("Signed int8:", a)
fmt.Println("Unsigned uint8:", b)
Output:
Signed int8: -128
Unsigned uint8: 255
2.2 Floating-Point Types
Go supports two types of floating-point numbers: float32 and float64.
float32: Approximation of floating-point numbers with 32 bits.
float64: Approximation of floating-point numbers with 64 bits (more precision).
Example:
package main
import "fmt"
func main() {
var pi float32 = 3.14159
var e float64 = 2.718281828459045
fmt.Println("Float32 value:", pi)
fmt.Println("Float64 value:", e)
Output:
Float32 value: 3.14159
Float64 value: 2.718281828459045
2.3 Boolean Type
The bool type represents a boolean value which can either be true or false.
Example:
package main
import "fmt"
func main() {
var isGoAwesome bool = true
var isPythonBetter bool = false
fmt.Println("Is Go awesome?", isGoAwesome)
fmt.Println("Is Python better?", isPythonBetter)
}
Output:
Is Go awesome? true
Is Python better? false
1. String Type
A string in Go is a sequence of bytes. It represents text, and Go's string type is immutable
(cannot be modified once created).
Example:
package main
import "fmt"
func main() {
var greeting string = "Hello, Go!"
fmt.Println(greeting)
Output:
Hello, Go!
String Operations:
You can concatenate strings using the + operator.
Example:
package main
import "fmt"
func main() {
var firstName string = "Divya"
var lastName string = "Raj"
var fullName string = firstName + " " + lastName
fmt.Println("Full Name:", fullName)
Output:
Full Name: Divya Raj
2. Complex Numbers
Go supports complex numbers with two types: complex64 and complex128.
complex64: Consists of two float32 values (real and imaginary parts).
complex128: Consists of two float64 values.
Example:
package main
import "fmt"
func main() {
var c1 complex64 = complex(5, 7) // 5 + 7i
var c2 complex128 = complex(3.5, 2.5) // 3.5 + 2.5i
fmt.Println("Complex64:", c1)
fmt.Println("Complex128:", c2)
Output:
Complex64: (5+7i)
Complex128: (3.5+2.5i)
3. Rune Type (Alias for int32)
In Go, rune is a special data type used to represent a single Unicode
character. It's an alias for int32.
Example:
package main
import "fmt"
func main() {
var r rune = 'A'
fmt.Println("Rune value:", r) // Prints Unicode code point of 'A'
fmt.Println("Character:", string(r))
Output:
Rune value: 65
Character: A
4. Byte Type (Alias for uint8)
A byte in Go is an alias for uint8 and is used to represent binary data. It's
commonly used in slices of bytes for handling data streams, file input/output,
etc.
Example:
package main
import "fmt"
func main() {
var b byte = 65 // ASCII value of 'A'
fmt.Println("Byte value:", b)
fmt.Println("Character:", string(b))
Output:
Byte value: 65
Character: A
Important Note:
1. Commonly Used Basic Data Types in Go are as following
Integers (int)
Floating-point numbers (float64)
Boolean (bool)
String (string)
2. Less Commonly Used (But Still Important) are as following:
Complex Numbers (complex64, complex128)
Rune Type (rune)
Byte Type (byte)
UNIT -2- (08 Hrs)
2.1 Decision making
In Go programming, decision making refers to controlling the flow of a program based on
certain conditions.
The decision making structures include if, if-else, if-else if, switch, and conditional
expressions.
2.1.1 Types of Decision Making in Go
1. if Statement
2. if-else Statement
3. if-else if-else Statement
4. Nested if Statement
5. switch Statement
2.1.1.1 if Statement
The if statement is the simplest form of decision making, where a block of code is
executed if a specified condition evaluates to true.
Syntax:
if condition {
// code to execute if condition is true
Example:
package main
import "fmt"
func main() {
num := 10
if num > 5 {
fmt.Println("Number is greater than 5")
Output:
Number is greater than 5
2.1.1.2 if-else Statement
The if-else statement allows for two blocks of code: one block is executed if the
condition is true, and the other block is executed if the condition is false.
Syntax:
if condition {
// code to execute if condition is true
} else {
// code to execute if condition is false
Example:
package main
import "fmt"
func main() {
num := 3 // Equivalent to var num int = 3
if num > 5 {
fmt.Println("Number is greater than 5")
} else {
fmt.Println("Number is not greater than 5")
}
Output:
Number is not greater than 5
2.1.1.3 if-else if-else Statement
The if-else if-else ladder is used when you have multiple conditions to check.
The first block of code whose condition is true will be executed, and the rest will be
skipped.
Syntax:
if condition1 {
// code to execute if condition1 is true
} else if condition2 {
// code to execute if condition2 is true
} else {
// code to execute if none of the conditions are true
Example:
package main
import "fmt"
func main() {
num := 10
if num < 0 {
fmt.Println("Negative number")
} else if num == 0 {
fmt.Println("Zero")
} else {
fmt.Println("Positive number")
Output:
Positive number
2.1.1.4 Nested if Statement
You can nest if statements within other if or else blocks to check multiple conditions
sequentially.
Syntax:
if condition1 {
if condition2 {
// code to execute if both condition1 and condition2 are true
Example:
package main
import "fmt"
func main() {
num := 15
if num > 0 {
if num%2 == 0 {
fmt.Println("Positive even number")
} else {
fmt.Println("Positive odd number")
Output:
Positive odd number
2.1.1.5 Switch Statement
The switch statement is an efficient way to handle multiple possible values of an
expression.
Instead of writing multiple if statements, switch checks a value against several
possible cases.
Syntax:
switch expression {
case value1:
// code to execute if expression == value1
case value2:
// code to execute if expression == value2
default:
// code to execute if no case matches
Example:
package main
import "fmt"
func main() {
day := "Monday"
switch day {
case "Monday":
fmt.Println("Start of the workweek")
case "Friday":
fmt.Println("End of the workweek")
default:
fmt.Println("It's just another day")
Output:
Start of the workweek
Fallthrough in switch:
Go's switch statement doesn't automatically fall through to the next case.
If you want the execution to continue into the next case, you must explicitly use
fallthrough.
In Go, if you want the program to continue executing the next case block,
regardless of the next case's condition, you use the fallthrough keyword.
Key Advantages of fallthrough:
1. Simplifies Grouping of Cases:
o Sometimes, you may want similar actions for multiple cases. Instead of
duplicating code, you can use fallthrough to make the next case execute and
group related cases together.
2. Shared Logic Across Cases:
o You can write logic that is common to multiple cases and ensure it is executed
by using fallthrough. This can make the code more concise and readable.
3. Custom Control Over Flow:
o It gives the developer control over the flow of execution in a switch statement.
This is especially useful when a logical connection exists between cases, and
you want to intentionally continue executing the next case.
Example: Weekend Planner
package main
import "fmt"
func main() {
day := "Saturday"
switch day {
case "Friday":
fmt.Println("It's Friday! Time to wrap up work.")
fallthrough
case "Saturday":
fmt.Println("It's Saturday! Relax and have fun.")
fallthrough
case "Sunday":
fmt.Println("It's Sunday! Get ready for the new week.")
fallthrough
case "Monday":
fmt.Println("It's Monday! Back to work.")
default:
fmt.Println("It's a weekday. Keep working!")
}
Output:
It's Saturday! Relax and have fun.
It's Sunday! Get ready for the new week.
It's Monday! Back to work.
2.2 Loops
In Go programming, loops are used to execute a block of code repeatedly based on a
condition.
Go does not have while or do-while keywords. The language is designed with
simplicity in mind, and it provides only one looping construct: the for loop.
The for loop can be used in different ways to achieve various looping behaviours.
2.2.1 Types of Loops in Go
1. Basic For Loop
2. For Loop with Initialization and Post Statements
3. Infinite For Loop
4. For Loop as a While Loop
5. For Loop with Range
2.2.1.1 Basic For Loop
Continuously execute a block of code as long as the condition is true.
Syntax:
for condition {
// code to execute
Example:
package main
import "fmt"
func main() {
i := 1
for i <= 5 {
fmt.Println(i)
i++
Output:
2.2.1.2 For Loop with Initialization and Post Statements
A loop with initialization, a condition, and a post statement (e.g., increment or decrement) all
in one line.
Syntax:
for initialization; condition; post {
// code to execute
Example:
package main
import "fmt"
func main() {
for i := 1; i <= 5; i++ {
fmt.Println(i)
}
Output:
2.2.1.3 Infinite For Loop
A loop that runs indefinitely until a break statement is encountered or the program is
terminated.
Syntax:
for {
// code to execute
Example:
package main
import "fmt"
func main() {
i := 1
for {
fmt.Println(i)
if i >= 5 {
break
i++
}
Output:
2.2.1.4 For Loop as a While Loop
A loop that only includes a condition, functioning similarly to a while loop in other
languages.
Syntax:
for condition {
// code to execute
Example:
package main
import "fmt"
func main() {
i := 1
for i <= 5 {
fmt.Println(i)
i++
Output:
2
3
2.2.1.5 For Loop with Range
Iterate over slices, arrays, maps, or strings. Provides both index and value during
iteration.
Syntax:
for index, value := range collection {
// code to execute
Example with Slice [ Slices are a flexible and dynamic way to work with sequences of
elements in Go.]
package main
import "fmt"
func main() {
numbers := []int{10, 20, 30, 40, 50} // []int{} denotes a slice of integers with the specified
values
for index, value := range numbers {
fmt.Printf("Index: %d, Value: %d\n", index, value)
Output:
Index: 0, Value: 10
Index: 1, Value: 20
Index: 2, Value: 30
Index: 3, Value: 40
Index: 4, Value: 50
2.3 Pointers
In Go, pointers are a powerful feature that allows you to work directly with memory
addresses.
A pointer is a variable that stores the memory address of another variable. By using
pointers, you can access and manipulate the value stored at a specific memory
location.
2.3.1 Basic Concepts
2.3.1.1 Pointer Declaration
A pointer variable is declared by specifying the type of the value it points to followed
by an asterisk (*).
Syntax:
var ptr *int // This declares a pointer to an int type.
2.3.1.2 Getting a Pointer
Use the address-of operator (&) to get the memory address of a variable
Syntax:
var x int = 10
var ptr *int = &x
Here, ptr holds the address of variable x.
2.3.1.3 Dereferencing a Pointer
Use the dereference operator (*) to access the value at the memory address pointed to
by the pointer.
Syntax:
var value int = *ptr
This retrieves the value stored at the address contained in ptr.
Basic Pointer Example:
package main
import "fmt"
func main() {
var a int = 10
var ptr *int = &a // Pointer to the variable 'a'
fmt.Println("Value of a:", a) // Output: Value of a: 10
fmt.Println("Address of a:", ptr) // Output: Address of a: <memory address>
fmt.Println("Value at address:", *ptr) // Output: Value at address: 10
*ptr = 20 // Modify the value at the memory address pointed by ptr
fmt.Println("New value of a:", a) // Output: New value of a: 20
Pointer with Functions:
Pointers are often used to pass variables to functions by reference, allowing functions
to modify the original variable.
package main
import "fmt"
func updateValue(val *int) {
*val = 100 // Modify the value at the address pointed by val
func main() {
var num int = 10
fmt.Println("Original value:", num) // Output: Original value: 10
updateValue(&num) // Pass the address of num to the function
fmt.Println("Updated value:", num) // Output: Updated value: 100
2.4 Composite types
In Go, composite types are data types that are composed of other types.
They allow you to create complex data structures by combining simpler types.
2.4.1 Types of Composite Types
Arrays
Slices
Maps
Structs
Channels.
2.4.1.1 Arrays
Arrays are fixed-size collections of elements of the same type.
The size of an array is part of its type, and once created, the size cannot be changed.
Syntax:
var arr [5]int // Array of 5 integers
Example:
package main
import "fmt"
func main() {
var arr [3]int = [3]int{1, 2, 3}
fmt.Println(arr) // Output: [1 2 3]
2.4.1.2 Slices
Slices are more flexible than arrays.
They are dynamically-sized and can grow or shrink as needed.
A slice is essentially a view into an array.
Syntax:
var slice []int // Slice of integers
Example:
package main
import "fmt"
func main() {
slice := []int{1, 2, 3}
fmt.Println(slice) // Output: [1 2 3]
slice = append(slice, 4) // Add an element
fmt.Println(slice) // Output: [1 2 3 4]
2.4.1.3 Maps
Maps are unordered collections of key-value pairs.
Each key is unique, and maps provide fast lookups, additions, and deletions of
elements.
Syntax:
var m map[string]int // Map with string keys and int values
Example:
package main
import "fmt"
func main() {
m := make(map[string]int)
m["one"] = 1
m["two"] = 2
fmt.Println(m) // Output: map[one:1 two:2]
fmt.Println("Value for key 'one':", m["one"]) // Output: Value for key 'one': 1
2.4.1.4 Structs
Structs are composite types that group together variables (fields) under a single name.
Each field in a struct can have a different type.
Syntax:
type Person struct {
Name string
Age int
Example:
package main
import "fmt"
type Person struct {
Name string
Age int
func main() {
p := Person{Name: "Alice", Age: 30}
fmt.Println(p) // Output: {Alice 30}
2.4.1.5 Channels
Channels are used for communication between goroutines.
They provide a way to synchronize and transfer data safely.
Syntax:
var ch chan int // Channel of integers
Example:
package main
import "fmt"
func main() {
ch := make(chan int)
go func() {
ch <- 42 // Send data to the channel
}()
value := <-ch // Receive data from the channel
fmt.Println(value) // Output: 42
UNIT -3- (8 Hrs)
3.1 Functions in Go
Functions in Go are fundamental building blocks that encapsulate code into reusable
units.
Functions can take parameters, return values, and be used to structure and organize
your code effectively.
3.1.1 Defining a Function
To define a function in Go, you use the func keyword followed by the function
name, parameters (if any), and the return type (if any).
The body of the function is enclosed in curly braces {}.
Syntax:
func functionName(parameters) returnType {
// function body
Example:
package main
import "fmt"
// Function with no parameters and no return value
func greet() {
fmt.Println("Hello, World!")
// Function with parameters and return value
func add(a int, b int) int {
return a + b
func main() {
greet() // Output: Hello, World!
result := add(5, 3)
fmt.Println("Sum:", result) // Output: Sum: 8
}
3.1.2 Function Parameters and Return Types
Parameters:
Functions can take zero or more parameters.
Each parameter must have a type, and multiple parameters are separated by commas.
Example:
func multiply(x int, y int) int {
return x * y
Return Types
Functions can return zero or more values.
If a function returns multiple values, they are separated by commas.
Example:
func divide(x int, y int) (int, int) {
quotient := x / y
remainder := x % y
return quotient, remainder
3.1.3 Multiple arguments in a Function
Multiple arguments can be passed inside a function.
Example:
package main
import "fmt"
func main() {
showAge("Chiru", 5) // prints "Chiru is 5 years old."
fmt.Println(multiplyTwoNumbers(12, 23)) // prints 276
}
func showAge(name string, age int) {
fmt.Printf("%s is %d years old.\n", name, age)
func multiplyTwoNumbers(x, y int) int { // same type of arguments
return x*y
Output:
Chiru is 5 years old.
276
3.1.4 Go Function with multiple return values
A function can return as many values as you want.
package main
func main() {
vAdd, vSub := addSub(35, 25)
fmt.Printf("35 + 25 = %d\n", vAdd) // prints "35 + 25 = 60"
fmt.Printf("35 - 25 = %d\n", vSub) // prints "35 - 25 = 10"
func addSub(x, y int) (int, int) { // multiple return values (int, int)
return x+y, x-y
Output:
35 + 25 = 60
35 - 25 = 10
3.1.5 Named return values in Go
Function return values can be named in Golang.
It allows mentioning the names of the variables
Example:
package main
import "fmt"
func main() {
fmt.Println(divby10(100))
func divby10(num int) (res int) {
res = num/10
return res
Output:
10
3.1.6 Go Functions as call by “value” and “reference”
In Go, a function can take a parameter by value or reference.
Example:
package main
import "fmt"
func main() {
val := 12
fmt.Printf("The value before function call is %d\n", val)
changeValue(val) // does not change value
changeValueByRef(&val) //changes value
fmt.Printf("The value after function call is %d\n", val)
func changeValue(num int) {
num = 42
func changeValueByRef(num *int) {
*num = 42
Output:
The value before function call is 12
The value after function call is 42
3.1.7 Returning an error from the function
A function can return an error. Errors are a way to show that unexpected thing
happened. So, it is necessary to have it.
3.1.8 Using the blank identifier
The blank identifier is used because Go gives a warning when a variable is declared
but never used. The syntax is to use “_” to assign the value.
Example:
package main
import "fmt"
func main() {
j, _ := returnTwoNumbers() // ignores the second return value
fmt.Println(j)
}
func returnTwoNumbers() (int, int) {
return 12, 23
}
3.1.9 Anonymous functions
Since Go supports First Class Functions, that means you can assign a function to a
variable or even invoke it immediately.
Example:
package main
import "fmt"
func main() {
getMod := func(a, b int) (int) { // declare it
return a%b
fmt.Println(getMod(12, 5)) // prints 2
// call by its name
3.1.10 Immediate invocation of a function
In the below code an anonymous function is immediately invoked.
Example:
package main
import "fmt"
func main() {
func(name string) {
fmt.Printf("Hello, %s", name)
}("John") // prints "Hello, John"
3.1.11 The “defer” keyword
“Defer” is a keyword to delay function call till surrounding function returns.
Example:
package main
import "fmt"
func main() {
defer fmt.Println("before this.") // runs at the end
fmt.Println("This is printed ") // runs first
3.1.12 User-defined function types
User-defined function types are types that can be identified as a function.
Example:
package main
import "fmt"
type First func(int) int // declare type
func getFunction() First { // use it
return func(val int) int {
return val * 5
func main() {
f := getFunction() // returns a function of type First
fmt.Println(f(12))
3.1.13 Functions as arguments
Functions in Go can be passed as arguments. This allows us to create Higher Order
Functions.
3.1.14 Returning functions from function
A function can return another function as well. Here is how to do that.
Example:
package main
import "fmt"
func main() {
f := getFunction("John") // returns a function
f() // prints "Hello, John"
func getFunction(name string) func() {
return func() {
fmt.Printf("Hello, %s", name)
3.1.15 Function closures
Function closures are an important concept to understand.
As it will help create better code and increase your understanding of the language.
So, what is a closure? A closure is a function that is bound to the variables in its
scope.
That means each closure has its own scope.
3.2 The init function in Golang
init() function is just like the main function, does not take any argument nor return
anything.
This function is present in every package and this function is called when the package
is initialized.
This function is declared implicitly, so you cannot reference it from anywhere and
you are allowed to create multiple init() function in the same program and they
execute in the order they are created.
You are allowed to create init() function anywhere in the program and they are called
in lexical file name order (Alphabetical Order).
3.2.1 How to use the init function in Go?
The init function in Go should be used to do the tasks we want to do before doing all
other things in that file.
That means it is more suited to tasks like initializations.
Example:
package main
import (
"fmt"
func init() {
fmt.Println("Runs first")
func main() {
fmt.Println("Hello, World")
// Runs first
// Hello, World
3.2.3 Order of the init functions
The order of the init functions matter.
The way they are declared in the same order they are executed.
Example:
package main
import "fmt"
func init() {
fmt.Println("Runs first")
func init() {
fmt.Println("Runs second")
func main() {
fmt.Println("Hello, World")
// output:
// Runs first
// Runs second
// Runs last
// Hello, World
func init() {
fmt.Println("Runs last")
Observe that even though one of the init function has been declared after the main, it
still runs before main and maintains the order.
3.2.4 Why is init useful?
The init functions are extremely useful due to the fact that they are
executed immediately before any other functions from the package
and they maintain the order of declaration and execute in the same
order.
This helps create programs that maintain a steady flow of execution.
UNIT -4- (08 Hrs)
4.1 Methods in Go
In Go, methods are functions with a special receiver argument.
This allows you to define functions that can be called on instances of a specific type
(often a struct).
Methods allow you to associate behavior with data, which is similar to classes in
object-oriented languages.
Syntax of Methods:
func (receiverName ReceiverType) methodName(parameters) returnType {
// method body
So, when we want to call the function we simply do receiver.funcName(arg).
This allows Go to do the OOP-like method call.
4.1.1 What is a receiver?
A receiver is essentially just a type that can directly call the function.
Here is an example of a struct type having a method.
Here the struct Bird is the receiver. That means any object of type Bird can call
the function Fly. T
he receiver’s declaration should be in the same package that of the method
otherwise, it won’t work.
Example of a Method:
package main
import "fmt"
type Bird struct{
name string
}
// declare method
func (b Bird)Fly() {
fmt.Println(b.name, "is flying...")
}
func main() {
b := Bird{"Raven"}
// call method
b.Fly() // Raven is flying...
}
4.1.2 Why use receivers?
Receivers allow us to write function calls in an OOP manner.
That means whenever an object of some type is created that type can
call the function from itself.
Example:
package main
import "fmt"
type Person struct{
name string
func (p Person)Name(){
fmt.Println(p.name)
func main() {
// create object
p := Person{"Jack"}
// call method
p.Name() // Jack
4.1.3 Receiver types
There are two types of receivers that are available in Go.
The value receivers and the pointer receivers.
Value Receiver (a copy of the value).
When you use a value receiver, the method operates on a copy of the value,
meaning changes made inside the method do not affect the original value.
Pointer Receiver (a reference to the value, allowing modifications).
A pointer receiver operates on the actual value, allowing you to modify the
original data.
Example:
package main
import "fmt"
type Animal struct{
name string
}
func (a Animal)Run(){
fmt.Println(a.name, "is running...")
}
func (a *Animal)RunFaster(){
fmt.Println(a.name, "is running...")
}
func main() {
a := Animal{"Lion"}
a.Run() // Lion is running...
a.RunFaster() // Lion is running...
}
4.1.4 Methods on structs
Methods can be defined by structs.
It is really useful to do so since structs are the closest thing to a class in Go.
They allow data encapsulation and with the methods described they will behave as
a class does in an OOP language.
Example:
package main
import "fmt"
type Human struct{
name string
age int
func (h Human)Describe() {
fmt.Println(h.name, "is", h.age, "years old.")
func main() {
h := Human{"John", 23}
h.Describe() // John is 23 years old.
4.2 Golang Methods benefits
Methods have advantages over regular functions.
Functions with the same name are not allowed in the same package, but methods
can have the same name if their receivers are different.
Multiple structs can have methods with the same name.
This feature enables Go to support object-oriented behavior.
UNIT -5- (08 Hrs)
5.1 Go Interfaces
In general programming interfaces are contracts that have a set of functions to be
implemented to fulfill that contract.
Go is no different. Go has great support for interfaces and they are implemented in
an implicit way.
They allow polymorphism in Go.
5.2 What is an Interface?
An interface is an abstract concept which enables polymorphism in Go.
A variable of that interface can hold the value that implements the type.
Type assertion is used to get the underlying concrete value as we will see in this
post.
5.2.1 Declaring an interface in Golang
An interface is declared as a type. Here is the declaration that is used to declare
an interface.
type interfaceName interface{}
5.2.2 Zero-value of an interface
The zero value of an interface is nil. That means it holds no value and type.
Example:
package main
import "fmt"
func main() {
var a interface{}
fmt.Println(a) // <nil>
5.2.3 The empty interface in Go
An interface is empty if it has no functions at all.
An empty interface holds any type.
That’s why it is extremely useful in many cases. Below is the declaration of an
empty interface.
var i interface{}
5.3 Implementing an interface in Golang
An interface is implemented when the type has implemented the functions of the
interface.
Example:
package main
import "fmt"
type Person interface{
greet() string
type Human struct{
Name string
func (h *Human)greet() string {
return "Hi, I am " + h.Name
func isAPerson(h Person) {
fmt.Println(h.greet())
func main() {
var a = Human{"John"}
fmt.Println(a.greet()) // Hi, I am John
// below function will only work
// if a is also a person.
// Here we can see polymorphism in action.
isAPerson(&a) // Hi, I am John
5.4 Implementing multiple interfaces in Go
Multiple interfaces can be implemented at the same time.
If all the functions are all implemented then the type implements all the interfaces.
Below the type, the bird type implements both the interfaces by implementing the
functions.
Example:
package main
import (
"fmt"
"reflect"
type Flyer interface{
fly() string
type Walker interface{
walk() string
}
type Bird struct{
Name string
func (b *Bird)fly() string{
return "Flying..."
func (b *Bird)walk() string{
return "Walking..."
func main() {
var b = Bird{"Chirper"}
fmt.Println(b.fly()) // Flying...
fmt.Println(b.walk()) // Walking...
5.5 Interface Composition
In Go, interfaces can be composed of other interfaces.
This is called interface composition, and it allows building more complex
interfaces from simpler ones.
Example:
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
type ReadWriter interface {
Reader
Writer
}
Here, the ReadWriter interface includes both Reader and Writer interfaces.
5.6 Values in an interface
Interface values have a concrete value and a dynamic type.
Example:
package main
import (
"fmt"
type Flyer interface{
fly() string
type Walker interface{
walk() string
type Bird struct{
Name string
}
func (b *Bird)fly() string{
return "Flying..."
func (b *Bird)walk() string{
return "Walking..."
func main() {
var b = Bird{"Chirper"}
// %v for value and %T for type
fmt.Printf("%v --> %T", b, b) // {Chirper} --> main.Bird
In the code above chirper is of type Bird but has a concrete value
of {Chirpir}.
5.7 Type assertion using the interface
Type assertion is a way to get the underlying value an interface holds.
This means if an interface variable is assigned a string then the underlying
value it holds is the string.
Example:
package main
import (
"fmt"
)
type B struct{
s string
func main() {
var i interface{} = B{"a sample string"}
fmt.Println(i.(B)) // {a sample string}
5.8 Type switch using an interface
Type switches are an extremely similar control structure like the switch-cases, the
only difference is here the interface type is used to switch between different
conditions.
Example:
package main
import (
"fmt"
func checkType(i interface{}) {
switch i.(type) { // the switch uses the type of the interface
case int:
fmt.Println("Int")
case string:
fmt.Println("String")
default:
fmt.Println("Other")
}
func main() {
var i interface{} = "A string"
checkType(i) // String
5.9 Equality of interface values
The interface values can be equal if any of the conditions shown below are true.
They both are nil.
They have the same underlying concrete values and the same dynamic
type.
Example:
package main
import (
"fmt"
func isEqual(i interface{}, j interface{}) {
if(i == j) {
fmt.Println("Equal")
} else {
fmt.Println("Inequal")
func main() {
var i interface{}
var j interface{}
isEqual(i, j) // Equal
var a interface{} = "A string"
var b interface{} = "A string"
isEqual(a, b) // Equal
5.10 Using interfaces with functions
Interfaces can be passed to functions just like any other type. Here is an example
showing the usage of the interface with functions. A great advantage when using an
interface is that it allows any type of argument as we can see in this code below.
Example:
package main
import (
"fmt"
func f(i interface{}) {
fmt.Printf("%T\n", i)
func main() {
var a interface{} = "a string"
var c int = 42
f(a) // string
f(c) // int
}
5.11 Uses of an interface
Interfaces are used in Go where polymorphism is needed.
In a function where multiple types can be passed an interface can be used.
Interfaces allow Go to have polymorphism.
Interfaces are a great feature in Go and should be used wisely.
LABORATORY EXERCISES
Program 1: Write a Go program that calculates the factorial of a number using iterative
and recursive approaches. Ensure the program handles large numbers efficiently.
Program Description:
What is Factorial?
The factorial of a number n (written as n!) is the product of all numbers from 1 to n.
For example, 5! = 5 × 4 × 3 × 2 × 1 = 120.
Iterative Approach:
In the iterative approach, we use a loop to multiply all the numbers from 1 to n. We
keep multiplying the result step by step until we get the factorial.
Recursive Approach:
The recursive approach works by breaking the problem into smaller pieces. We say
that n! = n × (n-1)!, so the function keeps calling itself for smaller numbers until it
reaches 1, where the recursion stops.
Handling Large Numbers:
Since factorials grow very large (e.g., 100! is a huge number), we use the math/big
package in Go. This package helps us handle big numbers that would otherwise
overflow standard integer types.
Program Output:
The program asks the user to enter a number.
It then calculates the factorial using both the iterative and recursive methods and
displays the result for each approach.
Code:
Variant 1: Calculating Factorial Using Iterative and Recursive Methods with Big
Integers in Go
package main
import (
"fmt"
"math/big"
// Iterative approach to calculate factorial using math/big for large numbers
func factorialIterative(n int64) *big.Int {
result := big.NewInt(1)
for i := int64(2); i <= n; i++ {
result.Mul(result, big.NewInt(i))
}
return result
// Recursive approach to calculate factorial using math/big for large numbers
func factorialRecursive(n int64) *big.Int {
// Base case: 0! = 1 and 1! = 1
if n == 0 || n == 1 {
return big.NewInt(1)
// Recursive case: n! = n * (n-1)!
result := big.NewInt(n)
return result.Mul(result, factorialRecursive(n-1))
func main() {
var num int64
fmt.Print("Enter a number: ")
fmt.Scan(&num)
// Iterative factorial
fmt.Printf("Factorial of %d (Iterative): %v\n", num, factorialIterative(num))
// Recursive factorial
fmt.Printf("Factorial of %d (Recursive): %v\n", num, factorialRecursive(num))
Output:
Variant 2: Factorial Calculation with Optimized Recursive and Iterative Methods in Go
package main
import (
"fmt"
"math/big"
// Iterative approach to calculate factorial
func factorialIterative(n int64) *big.Int {
result := big.NewInt(1)
for i := int64(2); i <= n; i++ {
result.Mul(result, big.NewInt(i))
return result
// Recursive approach with an early base case
func factorialRecursive(n int64) *big.Int {
result := big.NewInt(1)
if n > 1 {
result.Mul(big.NewInt(n), factorialRecursive(n-1))
return result
func main() {
var num int64
fmt.Print("Enter a number: ")
fmt.Scan(&num)
// Iterative factorial
fmt.Printf("Factorial of %d (Iterative): %v\n", num, factorialIterative(num))
// Recursive factorial
fmt.Printf("Factorial of %d (Recursive): %v\n", num, factorialRecursive(num))
Output:
Variant 3: Factorial Calculation Using Iterative and Recursive Approaches with Large
Input Warning in Go
package main
import (
"fmt"
"math/big"
// Iterative approach to calculate factorial
func factorialIterative(n int64) *big.Int {
result := big.NewInt(1)
for i := int64(2); i <= n; i++ {
result.Mul(result, big.NewInt(i))
return result
// Recursive approach with warning for large input
func factorialRecursive(n int64) *big.Int {
if n > 20 {
fmt.Println("Warning: This may take a while for large numbers!")
// Base case: 0! = 1 and 1! = 1
if n == 0 || n == 1 {
return big.NewInt(1)
result := big.NewInt(n)
return result.Mul(result, factorialRecursive(n-1))
func main() {
var num int64
fmt.Print("Enter a number: ")
fmt.Scan(&num)
// Iterative factorial
fmt.Printf("Factorial of %d (Iterative): %v\n", num, factorialIterative(num))
// Recursive factorial with warning
fmt.Printf("Factorial of %d (Recursive): %v\n", num, factorialRecursive(num))
Output:
Program 2: Implement a Go program that simulates a simple banking system. Use
structs to represent bank accounts with methods for deposit, withdrawal, and balance
checking.
Program Description:
This program simulates a simple banking system where users can perform basic banking
operations such as depositing, withdrawing money, and checking their account balance. It
uses a struct to represent a bank account, and methods to handle different operations.
Key Elements:
Bank Account Struct:
The BankAccount struct represents a bank account, containing fields like the account holder's
name and the current balance.
Deposit Method:
The Deposit method allows the user to add money to their bank account. It takes an amount
as input, adds it to the current balance, and displays the deposited amount.
Withdraw Method:
The Withdraw method lets the user take money out of their account. It checks whether the
balance is sufficient before allowing the withdrawal. If the balance is too low, it informs the
user about insufficient funds.
Check Balance Method:
The CheckBalance method returns the current balance of the account. It helps the user to
verify how much money they have left after deposits and withdrawals.
Main Function:
In the main function, the user is prompted to input the account holder's name and the initial
balance.
The program then allows the user to perform one deposit and one withdrawal operation, with
dynamic inputs for both.
Finally, the updated balance is displayed.
This program provides a simple and clear structure for basic banking operations. It handles
common banking tasks efficiently by using methods attached to the BankAccount struct,
making the code clean and easy to understand.
Code:
Variant 1: Simple Bank Account Management System with Deposit, Withdrawal, and
Balance Checking in Go
package main
import "fmt"
// Define a struct to represent a BankAccount
type BankAccount struct {
accountHolder string
balance float64
// Method to deposit money into the account
func (b *BankAccount) Deposit(amount float64) {
b.balance += amount
fmt.Printf("Deposited: %.2f\n", amount)
// Method to withdraw money from the account
func (b *BankAccount) Withdraw(amount float64) {
if amount > b.balance {
fmt.Println("Insufficient funds!")
} else {
b.balance -= amount
fmt.Printf("Withdrawn: %.2f\n", amount)
// Method to check the current balance
func (b *BankAccount) CheckBalance() float64 {
return b.balance
func main() {
var accountHolder string
var initialBalance, depositAmount, withdrawAmount float64
// Get input for account holder's name and initial balance
fmt.Print("Enter the account holder's name: ")
fmt.Scanln(&accountHolder)
fmt.Print("Enter the initial balance: ")
fmt.Scanln(&initialBalance)
// Create a new bank account with dynamic input
account := BankAccount{accountHolder: accountHolder, balance: initialBalance}
// Deposit money into the account
fmt.Print("Enter the amount to deposit: ")
fmt.Scanln(&depositAmount)
account.Deposit(depositAmount)
// Withdraw money from the account
fmt.Print("Enter the amount to withdraw: ")
fmt.Scanln(&withdrawAmount)
account.Withdraw(withdrawAmount)
// Check and print the current balance
fmt.Printf("Current balance for %s: %.2f\n", account.accountHolder,
account.CheckBalance())
Output:
Variant 2: Basic Bank Account Operations in Go
package main
import "fmt"
// Define a struct to represent a BankAccount
type BankAccount struct {
accountHolder string
balance float64
// Method to deposit money into the account
func (b *BankAccount) Deposit(amount float64) {
b.balance += amount
fmt.Printf("Deposited: %.2f\n", amount)
// Method to withdraw money from the account
func (b *BankAccount) Withdraw(amount float64) {
if amount > b.balance {
fmt.Println("Insufficient funds!")
} else {
b.balance -= amount
fmt.Printf("Withdrawn: %.2f\n", amount)
}
// Method to check the current balance
func (b *BankAccount) CheckBalance() float64 {
return b.balance
func main() {
// Create a new bank account
account := BankAccount{accountHolder: "John Doe", balance: 1000.0}
// Deposit money into the account
account.Deposit(500)
// Try to withdraw money
account.Withdraw(300)
// Check the current balance
fmt.Printf("Current balance: %.2f\n", account.CheckBalance())
// Try to withdraw more than the available balance
account.Withdraw(1500)
// Check the balance again
fmt.Printf("Balance after withdrawal: %.2f\n", account.CheckBalance())
Output:
Variant 3: Multiple Transactions with a Loop
package main
import (
"fmt"
// Define a struct to represent a BankAccount
type BankAccount struct {
accountHolder string
balance float64
// Method to deposit money into the account
func (b *BankAccount) Deposit(amount float64) {
b.balance += amount
fmt.Printf("Deposited: %.2f\n", amount)
// Method to withdraw money from the account
func (b *BankAccount) Withdraw(amount float64) {
if amount > b.balance {
fmt.Println("Insufficient funds!")
} else {
b.balance -= amount
fmt.Printf("Withdrawn: %.2f\n", amount)
// Method to check the current balance
func (b *BankAccount) CheckBalance() float64 {
return b.balance
func main() {
var accountHolder string
var initialBalance, amount float64
var choice int
// Get input for account holder's name and initial balance
fmt.Print("Enter the account holder's name: ")
fmt.Scanln(&accountHolder)
fmt.Print("Enter the initial balance: ")
fmt.Scanln(&initialBalance)
// Create a new bank account with dynamic input
account := BankAccount{accountHolder: accountHolder, balance: initialBalance}
// Start a loop for multiple transactions
for {
fmt.Println("\nChoose an option:")
fmt.Println("1. Deposit")
fmt.Println("2. Withdraw")
fmt.Println("3. Check Balance")
fmt.Println("4. Exit")
fmt.Print("Enter your choice: ")
fmt.Scanln(&choice)
switch choice {
case 1:
// Deposit money into the account
fmt.Print("Enter the amount to deposit: ")
fmt.Scanln(&amount)
account.Deposit(amount)
case 2:
// Withdraw money from the account
fmt.Print("Enter the amount to withdraw: ")
fmt.Scanln(&amount)
account.Withdraw(amount)
case 3:
// Check and print the current balance
fmt.Printf("Current balance for %s: %.2f\n", account.accountHolder,
account.CheckBalance())
case 4:
// Exit the loop
fmt.Println("Exiting the program.")
return
default:
fmt.Println("Invalid choice. Please try again.")
Output:
Program 3: Create a Go program that reads a matrix of integers from the user and
checks if it forms a symmetric matrix. Use pointers and composite types effectively.
Program description:
General Description:
This program allows users to input a square matrix (same number of rows and columns) of
integers and checks whether the matrix is symmetric. A symmetric matrix is one where the
element at position [i][j] is equal to the element at [j][i] for all i and j. In other words, the
matrix is equal to its transpose.
Key Features:
User Input:
o The program prompts the user to enter the size of the matrix (an integer n for
an n x n matrix).
o It then reads the matrix elements from the user row by row.
Matrix Representation:
o Uses composite types like two-dimensional slices ([][]int) to store the matrix
elements.
o Pointers are used to pass the matrix to functions efficiently without copying
the entire matrix.
Symmetry Check:
o The program includes a function that checks for symmetry by comparing each
element matrix[i][j] with matrix[j][i].
o If all corresponding elements are equal, the matrix is declared symmetric;
otherwise, it is not.
Variants Provided:
1. Basic Implementation:
o Uses a simple function with pointers to check symmetry.
o Focuses on simplicity and direct comparison of matrix elements.
2. Struct-Based Implementation:
o Introduces a Matrix struct to encapsulate the matrix data and size.
o Methods are defined on the struct to perform operations like checking for
symmetry, enhancing code organization.
3. Pointer Optimization:
o Passes both the matrix and its size as pointers to optimize memory usage.
o Emphasizes efficient parameter passing and memory management.
Code:
Variant 1: Simple Symmetry Check Using a 2D Slice
package main
import "fmt"
// Function to check if a matrix is symmetric
func isSymmetric(matrix *[][]int, size int) bool {
for i := 0; i < size; i++ {
for j := 0; j < size; j++ {
if (*matrix)[i][j] != (*matrix)[j][i] {
return false
return true
func main() {
var size int
fmt.Print("Enter the size of the square matrix: ")
fmt.Scan(&size)
// Initialize a 2D slice for the matrix
matrix := make([][]int, size)
for i := range matrix {
matrix[i] = make([]int, size)
// Read matrix input from the user
fmt.Println("Enter the matrix elements row by row:")
for i := 0; i < size; i++ {
for j := 0; j < size; j++ {
fmt.Scan(&matrix[i][j])
// Check if the matrix is symmetric
if isSymmetric(&matrix, size) {
fmt.Println("The matrix is symmetric.")
} else {
fmt.Println("The matrix is not symmetric.")
Output:
Variant 2: Using a Separate Struct for the Matrix
package main
import "fmt"
// Define a struct for a matrix
type Matrix struct {
data [][]int
size int
// Function to check if the matrix is symmetric
func (m *Matrix) isSymmetric() bool {
for i := 0; i < m.size; i++ {
for j := 0; j < m.size; j++ {
if m.data[i][j] != m.data[j][i] {
return false
return true
func main() {
var size int
fmt.Print("Enter the size of the square matrix: ")
fmt.Scan(&size)
// Initialize a Matrix struct
matrix := Matrix{size: size, data: make([][]int, size)}
for i := range matrix.data {
matrix.data[i] = make([]int, size)
// Read matrix input from the user
fmt.Println("Enter the matrix elements row by row:")
for i := 0; i < size; i++ {
for j := 0; j < size; j++ {
fmt.Scan(&matrix.data[i][j])
// Check if the matrix is symmetric
if matrix.isSymmetric() {
fmt.Println("The matrix is symmetric.")
} else {
fmt.Println("The matrix is not symmetric.")
Output:
Variant 3 : Symmetry Check with Pointers for Efficient Memory Usage
package main
import "fmt"
// Function to check if a matrix is symmetric using pointer to matrix data
func isSymmetric(matrix *[][]int, size *int) bool {
for i := 0; i < *size; i++ {
for j := 0; j < *size; j++ {
if (*matrix)[i][j] != (*matrix)[j][i] {
return false
return true
func main() {
var size int
fmt.Print("Enter the size of the square matrix: ")
fmt.Scan(&size)
// Initialize a 2D slice for the matrix
matrix := make([][]int, size)
for i := range matrix {
matrix[i] = make([]int, size)
// Read matrix input from the user
fmt.Println("Enter the matrix elements row by row:")
for i := 0; i < size; i++ {
for j := 0; j < size; j++ {
fmt.Scan(&matrix[i][j])
}
// Check if the matrix is symmetric
if isSymmetric(&matrix, &size) {
fmt.Println("The matrix is symmetric.")
} else {
fmt.Println("The matrix is not symmetric.")
Output:
Program 4: Write a Go program that demonstrates the use of pointers to swap the
values of two integers. Ensure the program handles edge cases such as zero values.
Program Description:
This program demonstrates how to swap the values of two integers using pointers in Go.
Swapping is a fundamental operation where the values of two variables are exchanged. Using
pointers allows the swap function to modify the original variables directly.
Key Features:
User Input:
o The program prompts the user to enter two integers that they wish to swap.
o It reads these values and stores them in variables.
Pointer Usage:
o Pointers (*int) are used in the swap function to access and modify the original
variables' memory addresses.
o This ensures the changes made within the function affect the actual variables
passed from main.
Swap Function Implementations:
Variant 1: Using a Temporary Variable
o A straightforward method where a temporary variable holds one value during
the swap.
o Steps:
1. Store the value of the first variable in a temporary variable.
2. Assign the value of the second variable to the first variable.
3. Assign the temporary variable's value to the second variable.
Variant 2: Using Arithmetic Operations
o Eliminates the need for a temporary variable by using addition and
subtraction.
o Steps:
1. Add both values and store the result in the first variable.
2. Subtract the new first variable by the second variable to get the original
first value into the second variable.
3. Subtract the new first variable by the new second variable to get the
original second value into the first variable.
Variant 3: Using Bitwise XOR
o Uses the bitwise XOR operator to swap values without a temporary variable.
o Steps:
1. Apply XOR to both variables and store the result in the first variable.
2. Apply XOR between the new first variable and the second variable to
get the original first value into the second variable.
3. Apply XOR between the new first variable and the new second
variable to get the original second value into the first variable.
Edge Case Handling:
o All methods correctly handle edge cases, including when one or both integers
are zero.
o The swap logic ensures that the correct values are exchanged regardless of
input.
Variants Provided:
1. Basic Swap with Temporary Variable:
o Simplest and most intuitive method.
o Easy to understand and suitable for beginners learning about pointers.
2. Swap Using Arithmetic Operations:
o Demonstrates how arithmetic can be used creatively to swap values.
o Avoids extra memory allocation for a temporary variable.
3. Swap Using Bitwise XOR:
o Showcases bitwise operations, offering an efficient swap method.
o Useful in low-level programming where memory optimization is crucial.
Variant 1 : Basic Pointer Swap
package main
import "fmt"
// Function to swap two integers using pointers
func swap(a, b *int) {
temp := *a
*a = *b
*b = temp
func main() {
var x, y int
fmt.Print("Enter two integers: ")
fmt.Scan(&x, &y)
fmt.Printf("Before swap: x = %d, y = %d\n", x, y)
swap(&x, &y)
fmt.Printf("After swap: x = %d, y = %d\n", x, y)
Output:
Variant 2 : Swap with Inline Pointer Arithmetic
package main
import "fmt"
// Function to swap two integers using pointer arithmetic
func swap(a, b *int) {
*a = *a + *b
*b = *a - *b
*a = *a - *b
func main() {
var x, y int
fmt.Print("Enter two integers: ")
fmt.Scan(&x, &y)
fmt.Printf("Before swap: x = %d, y = %d\n", x, y)
swap(&x, &y)
fmt.Printf("After swap: x = %d, y = %d\n", x, y)
Output:
Variant 3 : Swap with Bitwise XOR
package main
import "fmt"
// Function to swap two integers using bitwise XOR
func swap(a, b *int) {
*a = *a ^ *b
*b = *a ^ *b
*a = *a ^ *b
func main() {
var x, y int
fmt.Print("Enter two integers: ")
fmt.Scan(&x, &y)
fmt.Printf("Before swap: x = %d, y = %d\n", x, y)
swap(&x, &y)
fmt.Printf("After swap: x = %d, y = %d\n", x, y)
Output:
Program 5: Develop a Go program that implements a recursive function to compute the
Fibonacci sequence up to a specified number. Optimize the function for efficiency.
Program Description:
This program computes the Fibonacci sequence up to a specified number of terms. The
Fibonacci sequence is a series of numbers where each number is the sum of the two
preceding ones, typically starting with 0 and 1. The sequence is defined as follows:
F(0) = 0
F(1) = 1
F(n) = F(n-1) + F(n-2) for n > 1
Key Features:
User Input: The program prompts the user to enter the number of terms they wish to
compute in the Fibonacci sequence.
Computational Approaches:
o Basic Recursive Method: A straightforward recursive function that computes
each Fibonacci number by recursively calling itself. While simple, this
approach can be inefficient for larger numbers due to redundant calculations.
o Memoized Recursive Method: An optimized version that uses memoization
to store already computed Fibonacci numbers in a map. This avoids repeated
calculations and significantly improves performance for larger inputs.
o Iterative Method: An efficient approach that calculates the Fibonacci
sequence using a loop. This method builds the sequence directly and is
optimal for large input sizes, eliminating the overhead of recursive function
calls.
Output: After computing the Fibonacci sequence, the program prints the numbers in
the sequence up to the specified number of terms.
Variant 1: Basic Recursive Fibonacci
package main
import "fmt"
// Recursive function to compute Fibonacci number
func fibonacci(n int) int {
if n <= 0 {
return 0
} else if n == 1 {
return 1
}
return fibonacci(n-1) + fibonacci(n-2)
func main() {
var num int
fmt.Print("Enter the number of Fibonacci terms to compute: ")
fmt.Scan(&num)
fmt.Printf("Fibonacci sequence up to %d terms:\n", num)
for i := 0; i < num; i++ {
fmt.Printf("%d ", fibonacci(i))
fmt.Println()
Output:
Variant 2: Memoized Recursive Fibonacci
package main
import "fmt"
// Memoization array to store Fibonacci numbers
var memo = make(map[int]int)
// Recursive function to compute Fibonacci number with memoization
func fibonacci(n int) int {
if n <= 0 {
return 0
} else if n == 1 {
return 1
if val, found := memo[n]; found {
return val
// Store the computed Fibonacci number in the map
memo[n] = fibonacci(n-1) + fibonacci(n-2)
return memo[n]
func main() {
var num int
fmt.Print("Enter the number of Fibonacci terms to compute: ")
fmt.Scan(&num)
fmt.Printf("Fibonacci sequence up to %d terms:\n", num)
for i := 0; i < num; i++ {
fmt.Printf("%d ", fibonacci(i))
fmt.Println()
Output:
Variant 3: Iterative Approach
package main
import "fmt"
// Iterative function to compute Fibonacci sequence
func fibonacci(n int) []int {
fib := make([]int, n)
if n >= 1 {
fib[0] = 0
if n >= 2 {
fib[1] = 1
for i := 2; i < n; i++ {
fib[i] = fib[i-1] + fib[i-2]
return fib
func main() {
var num int
fmt.Print("Enter the number of Fibonacci terms to compute: ")
fmt.Scan(&num)
fibSequence := fibonacci(num)
fmt.Printf("Fibonacci sequence up to %d terms:\n", num)
for _, value := range fibSequence {
fmt.Printf("%d ", value)
fmt.Println()
Output:
Program 6: Design a Go program that models a library management system.
Implement methods on a struct representing a book to handle borrowing, returning,
and availability status.
Program Description:
The Go program models a simple library management system using structs to represent
books. Each book has a title and availability status, and the program provides methods for
borrowing, returning, and checking availability. The book's availability changes when it is
borrowed or returned. The methods ensure that a book cannot be borrowed if it is unavailable
and cannot be returned if it was not borrowed.
Code:
Variant 1: Basic Struct Implementation
package main
import "fmt"
// Struct to represent a Book
type Book struct {
title string
available bool
// Method to borrow a book
func (b *Book) borrow() {
if b.available {
b.available = false
fmt.Println(b.title, "has been borrowed.")
} else {
fmt.Println(b.title, "is not available.")
// Method to return a book
func (b *Book) returnBook() {
if !b.available {
b.available = true
fmt.Println(b.title, "has been returned.")
} else {
fmt.Println(b.title, "was not borrowed.")
// Method to check availability
func (b *Book) checkAvailability() {
if b.available {
fmt.Println(b.title, "is available.")
} else {
fmt.Println(b.title, "is not available.")
func main() {
// Create a new book
book1 := Book{title: "Go Programming", available: true}
// Borrow and return the book
book1.checkAvailability()
book1.borrow()
book1.checkAvailability()
book1.returnBook()
book1.checkAvailability()
}
Output:
Variant 2: Struct with Multiple Books and Library Management
package main
import "fmt"
// Struct to represent a Book
type Book struct {
title string
available bool
// Method to borrow a book
func (b *Book) borrow() {
if b.available {
b.available = false
fmt.Println(b.title, "has been borrowed.")
} else {
fmt.Println(b.title, "is not available.")
// Method to return a book
func (b *Book) returnBook() {
if !b.available {
b.available = true
fmt.Println(b.title, "has been returned.")
} else {
fmt.Println(b.title, "was not borrowed.")
// Struct to represent a Library with multiple books
type Library struct {
books []Book
// Method to borrow a book by title
func (lib *Library) borrowBook(title string) {
for i := range lib.books {
if lib.books[i].title == title {
lib.books[i].borrow() // Correct method call
return
fmt.Println("Book not found.")
// Method to return a book by title
func (lib *Library) returnBook(title string) {
for i := range lib.books {
if lib.books[i].title == title {
lib.books[i].returnBook() // Correct method call
return
fmt.Println("Book not found.")
func main() {
// Create a library with two books
lib := Library{
books: []Book{
{title: "Go Programming", available: true},
{title: "Data Structures", available: true},
},
// Borrow and return books
lib.borrowBook("Go Programming")
lib.borrowBook("Data Structures")
lib.returnBook("Go Programming")
Output:
Variant 3: Borrowing History with Borrower Information
package main
import "fmt"
// Struct to represent a Book
type Book struct {
title string
available bool
borrower string
// Method to borrow a book with borrower's name
func (b *Book) borrow(name string) {
if b.available {
b.available = false
b.borrower = name
fmt.Printf("%s has been borrowed by %s.\n", b.title, name)
} else {
fmt.Printf("%s is not available, currently borrowed by %s.\n", b.title,
b.borrower)
// Method to return a book
func (b *Book) returnBook() {
if !b.available {
fmt.Printf("%s has been returned by %s.\n", b.title, b.borrower)
b.available = true
b.borrower = ""
} else {
fmt.Println(b.title, "was not borrowed.")
}
func main() {
// Create a new book
book := Book{title: "Go Programming", available: true}
// Borrow and return the book with borrower's name
book.borrow("Alice")
book.borrow("Bob") // Trying to borrow when already borrowed
book.returnBook()
book.borrow("Bob") // Now Bob can borrow
Output:
Program 7: Extend the library management system from the previous question by
implementing an interface for library items. Ensure books and other media can be
managed uniformly.
Program Description:
These programs extend the previous library management system by implementing an
interface (LibraryItem) that allows different types of items (e.g., books and DVDs) to be
managed uniformly. This makes the code more flexible and scalable.
Variant 1: Basic Library Item Interface
package main
import "fmt"
// Define the LibraryItem interface
type LibraryItem interface {
borrow()
returnItem()
checkAvailability()
// Book struct implementing LibraryItem interface
type Book struct {
title string
available bool
func (b *Book) borrow() {
if b.available {
b.available = false
fmt.Println(b.title, "has been borrowed.")
} else {
fmt.Println(b.title, "is not available.")
}
func (b *Book) returnItem() {
if !b.available {
b.available = true
fmt.Println(b.title, "has been returned.")
} else {
fmt.Println(b.title, "was not borrowed.")
func (b *Book) checkAvailability() {
if b.available {
fmt.Println(b.title, "is available.")
} else {
fmt.Println(b.title, "is not available.")
func main() {
// Create a new book
var item LibraryItem = &Book{title: "Go Programming", available: true}
// Borrow, check availability, and return the book
item.checkAvailability()
item.borrow()
item.checkAvailability()
item.returnItem()
}
Output:
Variant 2: Adding Another Media Type
package main
import "fmt"
// Define the LibraryItem interface
type LibraryItem interface {
borrow()
returnItem()
checkAvailability()
// Book struct implementing LibraryItem interface
type Book struct {
title string
available bool
func (b *Book) borrow() {
if b.available {
b.available = false
fmt.Println(b.title, "has been borrowed.")
} else {
fmt.Println(b.title, "is not available.")
}
func (b *Book) returnItem() {
if !b.available {
b.available = true
fmt.Println(b.title, "has been returned.")
} else {
fmt.Println(b.title, "was not borrowed.")
func (b *Book) checkAvailability() {
if b.available {
fmt.Println(b.title, "is available.")
} else {
fmt.Println(b.title, "is not available.")
// DVD struct implementing LibraryItem interface
type DVD struct {
title string
available bool
func (d *DVD) borrow() {
if d.available {
d.available = false
fmt.Println(d.title, "has been borrowed.")
} else {
fmt.Println(d.title, "is not available.")
func (d *DVD) returnItem() {
if !d.available {
d.available = true
fmt.Println(d.title, "has been returned.")
} else {
fmt.Println(d.title, "was not borrowed.")
func (d *DVD) checkAvailability() {
if d.available {
fmt.Println(d.title, "is available.")
} else {
fmt.Println(d.title, "is not available.")
func main() {
// Create a new book and DVD
var bookItem LibraryItem = &Book{title: "Go Programming", available: true}
var dvdItem LibraryItem = &DVD{title: "Inception", available: true}
// Borrow, check availability, and return both items
bookItem.checkAvailability()
bookItem.borrow()
bookItem.checkAvailability()
bookItem.returnItem()
dvdItem.checkAvailability()
dvdItem.borrow()
dvdItem.checkAvailability()
dvdItem.returnItem()
Output:
Variant 3: Managing Multiple Items in a Library
package main
import "fmt"
// Define the LibraryItem interface
type LibraryItem interface {
borrow()
returnItem()
checkAvailability()
// Book struct implementing LibraryItem interface
type Book struct {
title string
available bool
func (b *Book) borrow() {
if b.available {
b.available = false
fmt.Println(b.title, "has been borrowed.")
} else {
fmt.Println(b.title, "is not available.")
func (b *Book) returnItem() {
if !b.available {
b.available = true
fmt.Println(b.title, "has been returned.")
} else {
fmt.Println(b.title, "was not borrowed.")
func (b *Book) checkAvailability() {
if b.available {
fmt.Println(b.title, "is available.")
} else {
fmt.Println(b.title, "is not available.")
}
// DVD struct implementing LibraryItem interface
type DVD struct {
title string
available bool
func (d *DVD) borrow() {
if d.available {
d.available = false
fmt.Println(d.title, "has been borrowed.")
} else {
fmt.Println(d.title, "is not available.")
func (d *DVD) returnItem() {
if !d.available {
d.available = true
fmt.Println(d.title, "has been returned.")
} else {
fmt.Println(d.title, "was not borrowed.")
func (d *DVD) checkAvailability() {
if d.available {
fmt.Println(d.title, "is available.")
} else {
fmt.Println(d.title, "is not available.")
// Library struct to manage multiple LibraryItems
type Library struct {
items []LibraryItem
// Add item to the library
func (l *Library) addItem(item LibraryItem) {
l.items = append(l.items, item)
// Display availability of all items
func (l *Library) displayAvailability() {
for _, item := range l.items {
item.checkAvailability()
func main() {
// Create a library
lib := Library{}
// Add a book and a DVD to the library
lib.addItem(&Book{title: "Go Programming", available: true})
lib.addItem(&DVD{title: "Inception", available: true})
// Display availability of all items
lib.displayAvailability()
Output:
Program 8: Create a Go program that uses interfaces to define a shape hierarchy (e.g.,
square, circle). Implement methods to calculate area and perimeter for each shape and
demonstrate polymorphism
Program Description:
This Go program uses interfaces to define a shape hierarchy, where different shapes like
squares and circles implement methods for calculating area and perimeter. Polymorphism is
demonstrated by treating different shapes uniformly through the interface. Each variant
shows a different way to implement and interact with the shape interface.
Variant 1: Basic Shape Interface (Square and Circle)
package main
import (
"fmt"
"math"
// Define the Shape interface
type Shape interface {
area() float64
perimeter() float64
// Square struct implementing Shape interface
type Square struct {
side float64
func (s Square) area() float64 {
return s.side * s.side
func (s Square) perimeter() float64 {
return 4 * s.side
}
// Circle struct implementing Shape interface
type Circle struct {
radius float64
func (c Circle) area() float64 {
return math.Pi * c.radius * c.radius
func (c Circle) perimeter() float64 {
return 2 * math.Pi * c.radius
func main() {
// Create a square and circle
s := Square{side: 5}
c := Circle{radius: 3}
// Calculate and display area and perimeter for both shapes
fmt.Printf("Square: Area = %.2f, Perimeter = %.2f\n", s.area(), s.perimeter())
fmt.Printf("Circle: Area = %.2f, Perimeter = %.2f\n", c.area(), c.perimeter())
Output:
Variant 2: Using Pointers for Shape Structs
package main
import (
"fmt"
"math"
// Define the Shape interface
type Shape interface {
area() float64
perimeter() float64
// Square struct implementing Shape interface
type Square struct {
side float64
func (s *Square) area() float64 {
return s.side * s.side
func (s *Square) perimeter() float64 {
return 4 * s.side
// Circle struct implementing Shape interface
type Circle struct {
radius float64
func (c *Circle) area() float64 {
return math.Pi * c.radius * c.radius
}
func (c *Circle) perimeter() float64 {
return 2 * math.Pi * c.radius
func main() {
var squareSide, circleRadius float64
// Take user input for Square side length
fmt.Print("Enter the side of the square: ")
fmt.Scan(&squareSide)
// Take user input for Circle radius
fmt.Print("Enter the radius of the circle: ")
fmt.Scan(&circleRadius)
// Create a square and circle using pointers
s := &Square{side: squareSide}
c := &Circle{radius: circleRadius}
// Calculate and display area and perimeter for both shapes
fmt.Printf("Square: Area = %.2f, Perimeter = %.2f\n", s.area(), s.perimeter())
fmt.Printf("Circle: Area = %.2f, Perimeter = %.2f\n", c.area(), c.perimeter())
Output:
Variant 3: Adding a New Shape (Triangle)
package main
import (
"fmt"
"math"
// Define the Shape interface
type Shape interface {
area() float64
perimeter() float64
// Square struct implementing Shape interface
type Square struct {
side float64
func (s Square) area() float64 {
return s.side * s.side
func (s Square) perimeter() float64 {
return 4 * s.side
// Circle struct implementing Shape interface
type Circle struct {
radius float64
func (c Circle) area() float64 {
return math.Pi * c.radius * c.radius
}
func (c Circle) perimeter() float64 {
return 2 * math.Pi * c.radius
// Triangle struct implementing Shape interface
type Triangle struct {
base, height, sideA, sideB, sideC float64
func (t Triangle) area() float64 {
return 0.5 * t.base * t.height
func (t Triangle) perimeter() float64 {
return t.sideA + t.sideB + t.sideC
func main() {
// Create a square, circle, and triangle
s := Square{side: 3}
c := Circle{radius: 2}
t := Triangle{base: 3, height: 4, sideA: 3, sideB: 4, sideC: 5}
// Calculate and display area and perimeter for all shapes
fmt.Printf("Square: Area = %.2f, Perimeter = %.2f\n", s.area(), s.perimeter())
fmt.Printf("Circle: Area = %.2f, Perimeter = %.2f\n", c.area(), c.perimeter())
fmt.Printf("Triangle: Area = %.2f, Perimeter = %.2f\n", t.area(), t.perimeter())
Output: