🌐 Golang Community Vault
Welcome to Golang Community Archive, a community-driven digital archive designed to collect, organize, and preserve the vast knowledge, resources, and experiences from the Go programming ecosystem and beyond. Whether you're a beginner, job seeker, seasoned contributor, or mentor — this is the place where we give and receive knowledge.
🎯 Project Purpose
The Golang Community Vault is not just an archive, it's a vibrant, evolving repository that serves:
- 📚 Preservation of valuable community-generated content.
- 🤝 Collaboration to promote open knowledge sharing and growth.
- 🔎 Job Seekers & Learners can gain insights from real-world experiences.
- 🧠 Centralized Resources to gather knowledge and tools scattered across the web.
💬 Stay Connected & Grow With Us!
We believe in community-driven learning. Whether you're here to contribute, collaborate, or just explore — your presence makes a difference. 💛
Join the Best Golang Community Ever and become part of something bigger than just code!
🌐 Connect With Us
🌟 Platform | 📌 Join Link |
---|---|
💬 Discord | Join the Go Community on Discord – Real-time discussions, questions, support, and collab rooms. |
📘 Facebook Group | Join the Go Facebook Community – Casual Q&As, success stories, community posts, and announcements. |
🎥 YouTube Channel | Subscribe to GoWithHabib – Deep dives, tutorials, interviews, and community videos. |
🤝 Get Involved
✅ Share your stories, notes, code, or insights
✅ Help with templates, docs, automation, or structure
✅ Collaborate on our static site or web vault
✅ Be part of building something that helps thousands
✨ Together, We Learn & Grow
“Code fades. Community lasts.”
Let’s archive knowledge, share what we’ve learned, and help the next generation of Gophers grow. 🐹🚀
📂 Archive Categories
Here's a quick look at the structure of the archive, where each folder represents a key area of Golang knowledge, experience, and resources.
golang-community-vault/
├── 1-interview-qa/ # Real interview Q&A and topic-wise challenges
│ ├── company-wise/ # Interview questions by company (Google, etc.)
│ ├── topic-wise/ # Go concepts (goroutines, interfaces, etc.)
│ └── curated-challenges/ # Problem-solving & deep dives
├── 2-class-notes/ # Course notes & summaries
│ ├── university-notes/ # Academic notes from CS/SE courses
│ ├── bootcamp-notes/ # Bootcamp summaries
│ └── online-course-summaries/ # Udemy, Coursera, etc.
├── 3-project-archive/ # Real-world Golang projects
│ ├── cli-tools/ # Command-line Go utilities
│ ├── web-servers/ # REST/HTTP server projects
│ ├── microservices/ # Auth, DB, API services
│ └── misc-projects/ # Other cool stuff
├── 4-image-infographic-archive/ # Visual aids like diagrams, cheat sheets
│ ├── architecture-diagrams/
│ ├── cheat-sheets/
│ └── flowcharts/
├── 5-community-stories/ # Real experiences, job search, career switch
│ ├── job-search-experience/
│ ├── rejection-learnings/
│ └── career-switch-tales/
├── 6-package-archive/ # Community-built Go libraries and tools
│ ├── utils/
│ ├── api-clients/
│ ├── middleware/
│ └── tools-and-libs/
├── 7-community-blogs/ # Written insights from the community
│ ├── how-tos/
│ ├── internals/
│ ├── opinion-pieces/
│ └── tutorials/
├── 8-news-events/ # Updates from the Go world
│ ├── newsletters/
│ ├── conference-recaps/
│ ├── meetup-summaries/
│ └── hackathons/
├── 9-video-archive/ # Curated video learning
│ ├── tutorials/
│ ├── tech-talks/
│ ├── documentaries/
│ └── playlists/
├── 10-course-content/ # Full-length open-source Go courses
│ ├── community-courses/
│ ├── mini-moocs/
│ └── challenge-series/
├── 11-link-resource-archive/ # Curated bookmarks and links
│ ├── tooling/
│ ├── blogs/
│ ├── documentation/
│ ├── slide-decks/
│ └── benchmarks/
📁 Category Overview
Microservice | Description | Documentation Link |
---|---|---|
1-interview-qa/ | Real interview Q&A and Go-topic challenges | 🔗 Golang Interview Q&A - Bangla |
2-class-notes/ | Academic and bootcamp course notes & summaries | 🔗 Class Notes Documentation |
3-project-archive/ | Real-world Go projects (CLI, web, microservices) | 🔗 Project Archive Documentation |
4-image-infographic-archive/ | Diagrams, cheat sheets, flowcharts | 🔗 Visual Archive Documentation |
5-community-stories/ | Job search experiences, lessons, and career stories | 🔗 Community Stories Documentation |
6-package-archive/ | Go libraries, middleware, API clients, etc. | 🔗 Package Archive Documentation |
7-community-blogs/ | Blogs, how-tos, opinion pieces from the community | 🔗 Community Blogs Documentation |
8-news-events/ | Go community news, events, hackathons | 🔗 News & Events Documentation |
9-video-archive/ | Curated learning videos, tech talks, playlists | 🔗 Video Archive Documentation |
10-course-content/ | Full-length open-source Go courses | 🔗 Course Content Documentation |
11-link-resource-archive/ | Curated links to tools, documentation, benchmarks | 🔗 Link Resources Documentation |
comprehensive and detailed RBAC permission list Golang Community Vault platform. This will allow fine-grained control for various roles across all the directories and content types outlined in README.
🔒 Universal Permission Categories (Applicable to all modules)
Permission | Description |
---|---|
view:<resource> | Can view/read the resource (public or restricted) |
create:<resource> | Can create/upload new items |
edit:<resource> | Can update or modify existing items |
delete:<resource> | Can remove an item |
publish:<resource> | Can mark content as published (if there’s a review process) |
archive:<resource> | Can archive or unpublish without deletion |
feature:<resource> | Can mark content as featured |
comment:<resource> | Can comment on resource |
moderate:<resource> | Can manage others' comments and discussions |
rate:<resource> | Can give rating (if rating system exists) |
tag:<resource> | Can add/edit tags or metadata |
assign:<resource> | Can assign reviewers or contributors to a resource |
🔖 Resource-Specific Permissions
Here's a breakdown by directory and subtype:
1. interview-qa/
Permission | Applies to |
---|---|
curate:interview_qa | Can organize, categorize, and reorder Q&A content |
bulk_upload:interview_qa | Upload multiple Q&As via CSV or UI |
label:difficulty_level | Can assign difficulty labels (easy/med/hard) |
verify:interview_qa | Trusted users can verify accuracy of Q&A |
suggest_edit:interview_qa | Submit Q&A revisions for approval |
link:qa_to_topic | Link questions across topic-wise and company-wise sections |
2. class-notes/
Permission | Applies to |
---|---|
format:class_note | Format content (LaTeX, markdown support) |
translate:class_note | Upload alternate language versions |
rate:note_quality | Rate based on helpfulness/accuracy |
submit_note_review | Peer review notes |
merge_notes | Combine similar notes into one resource |
3. project-archive/
Permission | Applies to |
---|---|
link:project_github | Attach GitHub repo link |
mark:project_stable | Certify project as stable/maintained |
fork:community_project | Duplicate project into sandbox for experimentation |
assign:maintainer | Assign project maintainers |
create:project_tags | Define tags like "CLI", "REST", "gRPC" etc. |
4. image-infographic-archive/
Permission | Applies to |
---|---|
upload:image_infographic | Upload PNG/SVG/PDF |
optimize:image | Resize/compress for performance |
annotate:image | Add notes or highlight sections |
group:infographics | Create themes/sets (e.g., Goroutine Internals Set) |
5. community-stories/
Permission | Applies to |
---|---|
submit:story | Submit a personal or experience story |
moderate:story | Approve or reject stories |
tag:story_category | Label stories (job hunt, rejections, etc.) |
feature:story | Highlight on community page |
approve:anonymous_story | Allow anonymous publishing |
6. package-archive/
Permission | Applies to |
---|---|
upload:package_source | Upload zip/tarball or Git link |
verify:package_integrity | Ensure no malicious code |
test:package | Run CI on submitted code |
mark:package_deprecated | Deprecate old packages |
create:package_doc | Write documentation for package |
7. community-blogs/
Permission | Applies to |
---|---|
submit:blog_post | Write and submit a blog |
edit:others_blog | Allow editing of other authors' blogs (moderator only) |
review:blog_post | Can review before publishing |
pin:blog_post | Pin post to top of page |
8. news-events/
Permission | Applies to |
---|---|
submit:event | Submit conference or event |
create:event_recap | Summarize events |
organize:event_listing | Curate future/past events |
assign:event_host | Add moderators for meetups/hackathons |
9. video-archive/
Permission | Applies to |
---|---|
embed:video_link | Attach YouTube or local hosted video |
transcribe:video | Add subtitle or transcript |
review:video_content | Moderate for quality or relevance |
feature:video | Spotlight video on homepage |
clip:video_segment | Create mini-clips or highlights |
10. course-content/
Permission | Applies to |
---|---|
submit:course_module | Create lessons or sections |
assign:course_owner | Appoint course maintainer(s) |
review:course_content | Approve/reject modules |
track:course_progress | See student analytics (admin only) |
11. link-resource-archive/
Permission | Applies to |
---|---|
submit:link | Add blog/tool/documentation link |
validate:link | Check for broken/dead links |
approve:external_resource | Manual approval for outbound links |
organize:bookmark_list | Allow curating themed collections |
✅ Bonus System Permissions
Permission | Applies to |
---|---|
manage:users | Admin only — manage roles, bans, profile data |
manage:roles | Create/update roles and their permission sets |
audit:logs | View user activity logs |
backup:data | Export platform content |
toggle:maintenance_mode | Take platform down for maintenance |
view:analytics | See usage and traffic reports |
send:notifications | System-wide announcement access |
🧩 Tech Stack & Tools
This vault is powered by several modern tools and practices for collaboration, code sharing, and documentation. Feel free to explore more about our tech stack.
🌟 Inspiration & Vision
“Code fades. Community lasts.”
This archive is designed to support, uplift, and celebrate the Golang Community. It’s not just about sharing code — it’s about collecting collective knowledge, hard-won experiences, and stories that shape our journey. Whether you're new to Go or a veteran, this vault is your home.
🧩 Tech Stack (Future Web App Vision)
This vault is powered by several modern tools and practices for collaboration, code sharing, and documentation. Feel free to explore more about our tech stack:
If this turns into a community-driven web interface:
• Frontend: React / Svelte / Next.js / Vue
• Backend: Go
• Storage: GitHub + SQLite/Postgres
• Auth: GitHub OAuth (optional)
• Deployment: AWS
UI/UX ideas for the future web App
Most preferable one for now:
1. Modern Library-Style UI
- Homepage: A clean, minimalist grid of featured archives with a search bar in the center.
- Filters & Categories: Sidebar with quick access to categories (by year, author, tags, etc.).
- Reading Mode: Dark/light mode toggle, distraction-free fullscreen mode.
- Bookmarking & Notes: Users can highlight text and add personal notes to archives.
Other types of UI
2. Timeline-Based UI
3. Grid & Gallery UI
4. Terminal-Inspired UI
5. Tag-Based UI
6. Map-Based UI
7. AI-Assisted UI
8. Infinite Scroll vs. Pagination Debate
Contribution Guide
✍️ How to Contribute?
We're excited to have you contribute to the Golang Community Vault! Whether you’re adding resources, sharing your experiences, or helping to maintain content — you are adding to the growth and strength of our community.
🚀 Types of Contributions
We welcome a wide range of contributions! Here’s how you can help:
-
Knowledge Sharing
Contribute articles, tutorials, or reference material that can help others learn and grow. -
Real-world Experiences
Share your job search stories, career-switch insights, rejection learnings, or any other experiences that can inspire and educate others. -
Code & Projects
Upload your open-source Golang projects, libraries, tools, or code snippets that can benefit the community. -
Learning Resources
Contribute notes, video tutorials, course summaries, or any other educational content to help others learn Golang.
📚 Contributor’s Guides
-
For Non-Tech Contributions
No coding required! Learn how you can help with documentation, resources, and content.
🔗 Contributor’s Guide (No-Code) -
For Code Contributions
If you want to contribute code or projects, follow our code contribution guidelines.
🔗 Contributor’s Guide (Code)
📌 COMMIT STRATEGY
✅ Format:
[<type>] <short-description>
💡 Types:
feat
: New content or filefix
: Fixes formatting or broken linksdocs
: Changes to README, guidesrefactor
: Structural changes
🧪 Example Commits:
[feat] Add interview questions for GCP
[fix] Correct broken link in course summary
[docs] Add README to cli-tools
🧩 CONTRIBUTION TEMPLATES FOR GOLANG COMMUNITY VAULT
Welcome to the Golang Community Vault!
We’re excited to have your contributions. Here's how you can help:
📌 Guidelines:
- Fork the repo and create a new branch (name it
feat/<title>
orfix/<title>
). - Add your Markdown files to the appropriate subfolder.
- Follow our [README] For Complete Documentation.
- Ensure links are working and code is properly formatted.
- Commit strategy using our COMMIT STRATEGY.
- Submit a pull request using our PULL REQUEST Template.
📂 Folder Naming Convention:
- All folders must use
kebab-case
. - Use
README.md
inside folders for summaries.
📝 Markdown File Template
# [Title]
**Author:** @yourhandle
**Date:** YYYY-MM-DD
**Category:** e.g., interview-qa/topic-wise
**Tags:** [go, concurrency, channels]
---
## 🧠 Summary
_Brief explanation of the content._
## 🧩 Content
### Overview
### Key Concepts
### Code
```go
// Example snippet\`
```
📚 Resources
## ✅ Contribution Rules
- Must include summary, author, and tags
- Format code blocks
- External links must be verified
## 🔗 Links
- [Templates](../templates)
- [Static Site Preview](../site)
💡 Non-Tech Contributions (No code required!)
You can still make a huge impact without writing any code. Here’s how:
-
Content Contributions
Add value by submitting resources, notes, blog posts, or guides. You don’t need to write code to make a meaningful contribution! -
Community Engagement
Help grow the knowledge base by engaging with others. Review content, offer suggestions, and be a part of discussions that improve the Vault.
We accept many types of contributions:
- 🧠 Interview Content – Real-world Q&A, curated challenges, topic-wise notes.
- 📚 Class Notes – University, bootcamp, or online course summaries.
- 🖼️ Visual Resources – Architecture diagrams, cheat sheets, flowcharts.
- 📖 Blog Posts – How-tos, opinion pieces, technical deep-dives.
- 🎬 Videos – Tech talks, tutorials, playlists, or webinars.
- 📖 Personal Stories – Career transitions, rejections, job search journeys.
- 🔗 Curated Links – Tools, docs, slide decks, benchmarks.
✅ PULL REQUEST TEMPLATE
### 📘 Description
What this PR adds/fixes/improves.
### 📂 Related Issue
Closes #[issue-number]
### 🚀 Changes Made
- Added/Updated [category/file-name.md]
- Fixed formatting/link issues
### ✅ Checklist
- [ ] Follows contribution guidelines
- [ ] Uses correct Markdown format
- [ ] Tested rendering in preview
Mehraz Obaydullah
Microservice Documentation Template for each category, following a Domain-Driven Design (DDD) approach for your golang-community-vault
project:
# 📘 Microservice - 1-interview-qa
## 📌 Domain Context
This microservice belongs to the **Interview Q&A Domain**, responsible for organizing and serving real-world interview questions and structured problem-solving content. It reflects bounded contexts like company-specific Q&A, topic-wise Go concepts, and curated deep dives.
## 🧩 Subdomains
- `company-wise/` - Q&A by hiring companies (Google, Meta, etc.)
- `topic-wise/` - Q&A by technical concept (e.g., Goroutines, Channels)
- `curated-challenges/` - Problem-solving sets with expected patterns
## 🧪 Core Capabilities
- Serve categorized Markdown-based content for interviews
- Support contributor-submitted Q&A in structured format
- Enable easy search/navigation via tags and metadata
## 🏗️ Expected Structure - Coming Soon
## 🔄 Input/Output Contract
### Input
- Markdown files via pull requests
- Validated metadata in frontmatter (e.g., tags, difficulty, author)
### Output
- Rendered HTML pages for Docusaurus
- Searchable metadata (for filtering/search)
## ⚙️ Internal Models
```go
type InterviewQuestion struct {
Title string `json:"title"`
Company string `json:"company,omitempty"`
Topics []string `json:"topics"`
Difficulty string `json:"difficulty"` // easy | medium | hard
Author string `json:"author"`
Content string `json:"content"` // Markdown
}
🛠 Maintainers
GitHub Handle | Role |
---|---|
@username1 | Lead Maintainer |
@username2 | Domain Reviewer |
📂 Directory Ownership
This service owns:
interview-qa/**
📚 References
🐹 Golang Playground
Welcome to my Golang knowledge hub — a growing collection of experiments, course notes, and practical learnings as I dive deeper into Go 🚀
📂 Structure (will be updated in future)
golang/
├── experiment/
└── go-with-habib-class-notes/
🔬 experiment/
A sandbox for all my Go experiments. From testing features to quick problem-solving attempts, this folder is all about learning by doing.
📘 go-with-habib-class-notes/
Detailed notes and example code from the "Go with Habib" course. Organized by class, with code and key takeaways.
📌 What's Next?
-
Add more Go mini-projects and tools under
experiment/
- Continue documenting the Habib course in markdown
-
Add
README.md
for each class and experiment -
Eventually turn this entire
golang/
folder into part of thebytebook
mdBook
[Author: @ifrunruhin12 Date: 2025-05-01 Category: interview-qa/class-wise ]
Class 07: Hello, World!
📄 কোড:
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
🔍 ব্যাখ্যা:
✅ package main
- Go-তে প্রতিটি প্রোগ্রাম একটি প্যাকেজের অংশ।
main
প্যাকেজ মানে এটি একটি executable program এটি চালানো যাবে।- যদি
main
না দাও, তাহলে Go বুঝবে এটা লাইব্রেরি।
✅ import "fmt"
fmt
Go এর স্ট্যান্ডার্ড প্যাকেজ, যেটা input/output এর কাজ করে।- এখানে আমরা
fmt.Println
ব্যবহার করেছি স্ক্রিনে কিছু প্রিন্ট করতে।
✅ func main() { ... }
main()
ফাংশন হলো Go প্রোগ্রামের entry point।- প্রোগ্রাম চালালে প্রথমেই এই ফাংশনটি রান হয়।
✅ fmt.Println("Hello, World!")
- এটি Go এর স্ট্যান্ডার্ড ফাংশন যা স্ক্রিনে
"Hello, World!"
প্রিন্ট করে। Println
মানে print line এটি নতুন লাইনে প্রিন্ট করে।
🧠 মনে রাখার মতো কিছু বিষয়:
বিষয় | ব্যাখ্যা |
---|---|
package main | executable প্রোগ্রামের জন্য বাধ্যতামূলক |
import "fmt" | I/O operations এর জন্য দরকারি |
func main() | Go প্রোগ্রামের execution শুরু এখান থেকে |
fmt.Println() | কনসোলে কিছু প্রিন্ট করার জন্য ব্যবহৃত হয় |
🚀 রান করার নিয়ম (Go ইনস্টল থাকার পর):
go run (file name).go
Extra :
-
Go একটি compiled language, যার মানে হলো কোড compile হয়ে এক্সিকিউটেবল ফাইল তৈরি করে।
-
Go এর compiler খুব দ্রুত এবং lightweight।
-
Go concurrency-friendly, অর্থাৎ একই সাথে অনেক কাজ (goroutines) সহজে হ্যান্ডেল করতে পারে।
-
Go এ garbage collection থাকে, যা অপ্রয়োজনীয় মেমোরি নিজে থেকে ম্যানেজ করে।
-
Go এর syntax খুব সহজ এবং readable, যা নতুনদের জন্য শেখা সহজ করে তোলে।
[Author : @shahriar-em0n Date: 2025-06-09 Category: interview-qa/class-wise ]
Class 08: Variables and Data Types
Go একটি strongly typed এবং statically typed compiled language, যার ফলে প্রতিটি ভ্যারিয়েবলের টাইপ স্পষ্টভাবে নির্ধারিত এবং গুরুত্বপূর্ণ
🧠 Variable Declare করার নিয়ম
Go তে ভেরিয়েবল declare করার তিনটি পদ্ধতি আছে:
1. Short Variable Declaration (: =
)
Short declaration (:=
) শুধুমাত্র ফাংশনের ভেতরে ব্যবহার করা যায়:
func main() {
a := 10
}
- টাইপ উল্লেখ করতে হয় না, Go নিজে থেকে টাইপ নির্ধারণ করে নেয় (Type Inference)৷
2. Explicit Type Declaration
var x int = 10
- এখানে
x
explicitlyint
টাইপের বলে দেওয়া হয়েছে।
3. Implicit Type Declaration
var a = 10
- টাইপ উল্লেখ করা হয়নি, তবে
a
এর টাইপint
হিসাবে নির্ধারিত হবে ১০ দেখে।
📘 Data Types
Go ভাষায় বিভিন্ন ধরনের ডেটা টাইপ আছে, যেগুলো মূলত 3 টি ভাগে ভাগ করা যায়।
১. Numeric Types
Go-তে numeric types মূলত তিনটি ভাগে বিভক্ত থাকে।
Integer Types
Type | Size | Description |
---|---|---|
int | platform-dependent | সাধারন পূর্ণসংখ্যা |
int8 | 8-bit | -128 to 127 |
int16 | 16-bit | -32,768 to 32,767 |
int32 | 32-bit | -2,147,483,648 to 2,147,483,647 |
int64 | 64-bit | খুব বড় পূর্ণসংখ্যা |
uint | unsigned int | ধনাত্মক পূর্ণসংখ্যা |
uint8 | 0 to 255 | Unsigned 8-bit integer |
uint16 | 0 to 65535 | Unsigned 16-bit integer |
uint32 | 0 to 4 billion+ | Unsigned 32-bit |
uint64 | বিশাল ধনাত্মক সংখ্যা | Unsigned 64-bit |
Floating Point Types
Type | Description |
---|---|
float32 | 32-bit decimal |
float64 | 64-bit decimal (default) |
Complex Types
Type | Description |
---|---|
complex64 | Real + Imaginary (float32) |
complex128 | Real + Imaginary (float64) |
২. String Type
- Represents text.
var message string = "Hello, Go!"
৩. Boolean Type
- Holds either
true
orfalse
.
var isGoFun bool = true
✅ Summary Table
Category | Example Type |
---|---|
Numeric | int, float64 |
Boolean | bool |
String | string |
✅ Valid Examples with Different Data Types
a := 10 // int
a := 40.34 // float64
a := "Hello" // string
a := true // bool
a = false // bool (reassigned)
⚠️ Note: একই স্কোপে একই ভেরিয়েবলকে বারবার
:=
দিয়ে declare করা যাবে না।
🔒 Constant Declaration
const p = 100
const
দিয়ে declare করা ভেরিয়েবল পরিবর্তন করা যাবে না।
[Author : @shahriar-em0n Date: 2025-06-09 Category: interview-qa/class-wise ]
Class 09 : If else and switch
Go তে কন্ডিশনাল স্টেটমেন্ট ব্যবহৃত হয় সিদ্ধান্ত নেওয়ার জন্য। নিচে if
, else if
, else
, এবং switch
এর বিস্তারিত ব্যাখ্যা এবং উদাহরণ দেওয়া হলো।
✅ if Statement
package main
import "fmt"
func main() {
number := 10
if number > 5 {
fmt.Println("Number is greater than 5")
}
}
যদি
if
এর স্টেটমেন্ট সত্য হয়, তবে ব্লকের ভিতরের কোড এক্সিকিউট হবে।
✅ if-else Statement
package main
import "fmt"
func main() {
number1 := 3
if number1 > 5 {
fmt.Println("Greater than 5")
} else {
fmt.Println("5 or less")
}
}
যদি
if
এর স্টেটমেন্ট মিথ্যা হয়, তাহলেelse
ব্লকের কোড এক্সিকিউট হবে |
✅ if,else if, else Statement
package main
import "fmt"
func main() {
package main
import "fmt"
func main() {
age := 18 // বয়স ১৮ সেট করা হয়েছে
if age > 18 {
// যদি বয়স ১৮ এর বেশি হয়, তাহলে নিচের মেসেজ দেখা যাবে
fmt.Println("You are eligible to be married") // প্রাপ্তবয়স্ক, বিয়ের জন্য উপযুক্ত
} else if age < 18 {
// যদি বয়স ১৮ এর কম হয়, তাহলে এই অংশ এক্সিকিউট হবে
fmt.Println("You are not eligible to be married, but you can love someone") // নাবালক, প্রেম করা যেতে পারে
} else if age == 18 {
// যদি বয়স একদম ১৮ হয়, তাহলে এই অংশ এক্সিকিউট হবে
fmt.Println("You are just a teenager, not eligible to be married") // টিনএজার, বিয়ের জন্য ঠিক উপযুক্ত না
}
}
}
একাধিক স্টেটমেন্ট চেক করার জন্য
else if
ব্যবহার করা হয় | উপরের কোডে বয়স অনুসারে তিনটি ভিন্ন রেসপন্স দেখানো হয়েছে।
🔁 switch Statement
package main
import "fmt"
func main() {
day := 3 // day ভ্যারিয়েবলটি ৩ দেওয়া হয়েছে
switch day {
case 1:
fmt.Println("Sunday") // যদি day == 1 হয়, তাহলে Sunday প্রিন্ট হবে
case 2:
fmt.Println("Monday") // যদি day == 2 হয়, তাহলে Monday প্রিন্ট হবে
case 3:
fmt.Println("Tuesday") // যদি day == 3 হয়, তাহলে Tuesday প্রিন্ট হবে
default:
fmt.Println("Another day") // যদি কোন case না মিলে , তাহলে default অংশে চলে যাবে
}
}
switch
স্টেটমেন্ট অনেকগুলোif-else if
কে রিপ্লেস করতে পারে এবং কোডকে cleaner করে তোলে। এটি একটি নির্দিষ্ট ভ্যালুর উপর ভিত্তি করে বিভিন্ন আউটপুট দেয়।
⚠️ Note:
- Go তে
if
এবংswitch
ব্লকে ব্র্যাকেট{}
আবশ্যক। switch
ব্লকে প্রতিটি case এর পরেbreak
লিখতে হয় না, কারণ Go নিজেই implicity break করে দেয়, যদি নাfallthrough
ব্যবহার করা হবে |
[Author : @shahriar-em0n Date: 2025-06-11 Category: interview-qa/class-wise ]
Class 10 : Introduction to Functions
🔍 Function কী?
Function
(ফাংশন) হল কোডের একটি পুনঃব্যবহারযোগ্য ব্লক যা নির্দিষ্ট একটি কাজ করে।
যখন আমাদের একই কোড বারবার লেখা লাগে, তখন আমরা সেটাকে একটা ফাংশনের মধ্যে রেখে দিই।
এতে করে কোড clean হয়, readable হয় এবং বারবার ব্যবহার করা যায়।
🧠 Function কেন ব্যবহার করি?
- ✅ Reusability (একই কোড বারবার ব্যবহার করা যায়)
- ✅ Readability (কোড আরও পরিষ্কার হয়)
- ✅ Maintainability (বাগ ফিক্স করা বা পরিবর্তন সহজ হয়)
- ✅ Logic কে ছোট ছোট অংশে ভাগ করে বুঝতে সুবিধা হয়
🧪 উদাহরণ: দুটি সংখ্যার যোগফল বের করা
package main
import "fmt"
// এই ফাংশনটি দুটি সংখ্যা নেয় এবং তাদের যোগফল প্রিন্ট করে
func add(num1 int, num2 int){
sum := num1 + num2
fmt.Println(sum)
}
func main() {
a := 10
b := 20
add(a, b) // Output: 30
add(5, 7) // Output: 12
}
ব্যাখ্যা:
func add(num1 int, num2 int)
- এটি একটি function definition, যেখানেnum1
এবংnum2
হল parameters।sum := num1 + num2
- এখানে দুই সংখ্যার যোগফল বের করা হচ্ছে।fmt.Println(sum)
- যোগফল প্রিন্ট করা হচ্ছে।main()
ফাংশনের মধ্যেadd(a, b)
ব্যবহার করে আমরা ফাংশনটি কল করেছি।
[Author : @shahriar-em0n Date: 2025-06-11 Category: interview-qa/class-wise ]
📘 Class 11 : Function with Return Values and Types
Go তে ফাংশনের মাধ্যমে আমরা একটি অথবা একাধিক ভ্যালু রিটার্ন করতে পারি।। ফাংশন শুধু কাজ করেই শেষ নয় আমরা চাইলে ফাংশন থেকে ফলাফলও (result) ফিরে পেতে পারি। একে বলে Return Value।
Go-তে ফাংশন থেকে দুই ধরনের রিটার্ন হতে পারে:
- ✅ Single Return Value (একটি মান ফেরত দেয়)
- ✅ Multiple Return Values (একাধিক মান ফেরত দেয়)
🔹 Single Return Value
ফাংশন যখন একটি মাত্র ফলাফল ফেরত দেয়, তখন তাকে Single Return Function বলা হয়।
✅ উদাহরণঃ
package main
import "fmt"
// একক রিটার্ন ভ্যালু সহ ফাংশন
func add(num1 int, num2 int) int {
sum := num1 + num2
fmt.Println("ফাংশনের ভিতরে যোগফল:", sum)
return sum
}
func main() {
a := 10
b := 20
result := add(a, b) // রিটার্ন মানটি result এ রাখছি
fmt.Println("main ফাংশনে রিটার্ন মান:", result)
}
🔎 ব্যাখ্যাঃ
add()
ফাংশন দুটি ইনপুট নেয়:num1
এবংnum2
।- এটি তাদের যোগফল
sum
হিসেব করে ফেরত দেয়return sum
। main()
ফাংশনে এই রিটার্ন মানটিresult
ভ্যারিয়েবলে রাখা হয়।
🔹 Multiple Return Values
ফাংশন যদি একাধিক ফলাফল একসাথে ফেরত দেয়, তাহলে সেটাকে Multiple Return Function বলা হয়।
✅ উদাহরণঃ
package main
import "fmt"
// একাধিক রিটার্ন ভ্যালু সহ ফাংশন
func getNumbers(num1 int, num2 int) (int, int) {
sum := num1 + num2
mul := num1 * num2
return sum, mul
}
func main() {
a := 10
b := 20
// দুটি রিটার্ন মান আলাদা করে নিচ্ছি
p, q := getNumbers(a, b)
fmt.Println("যোগফল =", p)
fmt.Println("গুণফল =", q)
}
🔎 ব্যাখ্যাঃ
getNumbers()
ফাংশন দুটি ইনপুট নেয় এবং দুইটি আউটপুট দেয়: যোগফল (sum
) এবং গুণফল (mul
)।- আমরা
main()
ফাংশনেp, q := getNumbers(a, b)
ব্যবহার করে রিটার্ন মানগুলো আলাদা করে নিই।
✅ সংক্ষেপে মনে রাখুন:
Go প্রোগ্রামিং ভাষায় ফাংশন থেকে আমরা একটি বা একাধিক মান রিটার্ন করতে পারি।
ফাংশনের Return Value: Single vs Multiple
ধরন | রিটার্ন সংখ্যা | রিটার্ন টাইপ | কী ফেরত দেয়? | উদাহরণ ফাংশন | ডিক্লেয়ার করার ধরন |
---|---|---|---|---|---|
Single Return | ১টি মান | int | একটি পূর্ণসংখ্যা | add() | func add() int |
Single Return | ১টি মান | string | একটি স্ট্রিং | getName() | func getName() string |
Single Return | ১টি মান | rune | একটি ক্যারেক্টার | getChar() | func getChar() rune |
Single Return | ১টি মান | float64 | একটি ভাসমান সংখ্যা | getAverage() | func getAverage() float64 |
Multiple Return | একাধিক মান | (int, int) | দুইটি পূর্ণসংখ্যা | getNumbers() | func getNumbers() (int, int) |
Multiple Return | একাধিক মান | (string, int) | স্ট্রিং ও সংখ্যা | getUserInfo() | func getUserInfo() (string, int) |
সাধারণ Return টাইপ ব্যাখ্যা
int
- পূর্ণসংখ্যা (যেমন: 5, 100)float64
- দশমিক সংখ্যা (যেমন: 3.14, 9.81)string
- স্ট্রিং বা টেক্সট (যেমন: "Shahriar")rune
- একটি ইউনিকোড ক্যারেক্টার (যেমন: 'A', 'ক')
📝 নোট: Go ফাংশনে আমরা দুইটির বেশি মানও রিটার্ন করতে পারি - যেমন ৩টি বা তার বেশি মান। তবে এই টেবিল ও উদাহরণগুলোতে আমরা শুধুমাত্র দুটি মান রিটার্নের উদাহরণ দিয়েছি, যেন বিষয়টি সহজভাবে বোঝানো যায়। প্রয়োজনে ফাংশন থেকে আরও বেশি সংখ্যক মান রিটার্ন করাও সম্ভব এবং এটি পুরোপুরি বৈধ।
এভাবে Go ফাংশন return value এর মাধ্যমে কার্যকরভাবে তথ্য ফেরত দিতে পারে, যা কোডকে modular এবং পরিষ্কার করে তোলে।
Note
Go-তে ফাংশনের মাধ্যমে কোডকে পরিষ্কার ও পুনঃব্যবহারযোগ্য করা যায়। return value ব্যবহার করে আমরা ফাংশনের কাজের ফলাফল main() ফাংশনে এনে ব্যবহার করতে পারি। একাধিক মান ফেরত দেওয়ার ক্ষমতা Go ভাষাকে আরও শক্তিশালী করে তোলে।
[Author : @shahriar-em0n Date: 2025-06-13 Category: interview-qa/class-wise ]
📘 Class 12 : More Function Examples
এখানে আরও কিছু ফাংশনের উদাহরণ দেওয়া হলো।
✅ Function 1: printSomething()
এই ফাংশনটি কোন আর্গুমেন্ট নেয় না এবং কোন রিটার্ন ভ্যালুও দেয় না। শুধুমাত্র একটি লাইন প্রিন্ট করে।
📄 Code:
func printSomething(){
fmt.Println("Education must be free!")
}
🧠 ব্যাখ্যা:
printSomething()
ফাংশনটি কোন ইনপুট নেয় না।- এটি
fmt.Println()
ফাংশনের মাধ্যমে একটি মেসেজ প্রিন্ট করে দেয়।
✅ Function 2: sayHello(name string)
এই ফাংশনটি একটি প্যারামিটার (string টাইপের name
) নেয় এবং একটি স্বাগত বার্তা প্রিন্ট করে।
📄 Code:
func sayHello(name string){
fmt.Println("Welcome to the golang course, ", name)
}
🧠 ব্যাখ্যা:
sayHello
ফাংশনটি একটিname
ইনপুট নেয়, যাstring
টাইপের।- এরপর
fmt.Println()
ব্যবহার করে সেই নামসহ একটি মেসেজ প্রিন্ট করে।
🔁 Main Function
📄 Code:
func main() {
printSomething()
sayHello("Shahriar")
}
🧠 ব্যাখ্যা:
-
main()
ফাংশন হচ্ছে Go প্রোগ্রামের এন্ট্রি পয়েন্ট। -
এখানে প্রথমে
printSomething()
কল করা হয়েছে, তাই এটি"Education must be free!"
প্রিন্ট করবে। -
তারপর
sayHello("Shahriar")
কল করা হয়েছে, তাই এটি"Welcome to the golang course, Shahriar"
প্রিন্ট func showPrice(price float64){fmt.Println("The product price is: $", price)
}করবে।
🧾 সংক্ষেপে
ফাংশনের নাম | প্যারামিটার | কাজ | রিটার্ন |
---|---|---|---|
printSomething() | নাই | একটি মেসেজ প্রিন্ট করে | নাই |
sayHello(name string) | একটি স্ট্রিং | নামসহ মেসেজ প্রিন্ট করে | নাই |
[Author : @shahriar-em0n Date: 2025-06-13 Category: interview-qa/class-wise ]
📘 Class 13: Why Functions Are Needed?
✅ ১. কেন ফাংশন দরকার?
প্রোগ্রাম লেখার সময় অনেক সময় দেখা যায় একই ধরণের কাজ বারবার করতে হচ্ছে। যেমন: ইউজারের নাম নেওয়া, সংখ্যা নেওয়া, বা একটা মেসেজ প্রিন্ট করা।
👉 যদি এগুলো আমরা বারবার main()
ফাংশনের মধ্যে লিখি, তাহলে:
- কোড অনেক বড় ও জটিল হয়ে যায়
- একই কোড বারবার লিখতে হয় (repetition)
- কোড মেইনটেইন করা কঠিন হয়
📌 ফাংশন ব্যবহার করলে:
- কোড ছোট ছোট অংশে ভাগ করা যায় (Modular Code)
- একবার লিখে বারবার ব্যবহার করা যায় (Reusable)
- বোঝা এবং মেইনটেইন করা সহজ হয়
- বাগ (bug) ধরা ও ঠিক করা সহজ হয়
Example : ফাংশন ব্যবহার করার আগে
এখানে একটি প্রোগ্রাম দেখানো হয়েছে যেখানে কোন ফাংশন ব্যবহার করা হয়নি:
package main
import "fmt"
func main() {
// Print welcome message
fmt.Println("Welcome to the application")
// Get user name as input
var name string
fmt.Println("Enter your name - ")
fmt.Scanln(&name)
var num1 int
var num2 int
fmt.Println("Enter first number - ")
fmt.Scanln(&num1)
fmt.Println("Enter second number - ")
fmt.Scanln(&num2)
sum := num1 + num2
// display results
fmt.Println("Hello, ", name)
fmt.Println("Summation = ", sum)
// print a goodbye message
fmt.Println("Thank you for using the application")
fmt.Println("Goodbye")
}
🧠 সমস্যা:
- একই
main()
ফাংশনে সবকিছু একত্রে থাকায় কোডটি বড় ও জটিল হয়ে গেছে - পুনরায় ব্যবহারযোগ্যতা নেই
- মেইনটেন করা কঠিন
✅ ফাংশন ব্যবহার করার পরে
একই কাজকে ফাংশনের মাধ্যমে ভাগ করে সহজ করা হয়েছে:
package main
import "fmt"
func printWelcomeMessage() {
fmt.Println("Welcome to the application")
}
func getUserName() string {
var name string
fmt.Println("Enter your name - ")
fmt.Scanln(&name)
return name
}
func getTowNumbers() (int, int) {
var num1 int
var num2 int
fmt.Println("Enter first number - ")
fmt.Scanln(&num1)
fmt.Println("Enter second number - ")
fmt.Scanln(&num2)-
return num1, num2
}
func add(num1 int, num2 int) int {
sum := num1 + num2
return sum
}
func display(name string, sum int) {
fmt.Println("Hello, ", name)
fmt.Println("Summation = ", sum)
}
func printGoodByeMessage() {
fmt.Println("Thank you for using the application")
fmt.Println("Goodbye")
}
func main() {
printWelcomeMessage()
name := getUserName()
num1, num2 := getTowNumbers()
sum := add(num1, num2)
display(name, sum)
printGoodByeMessage()
}
✅ সুবিধা:
- প্রতিটি কাজ আলাদা ফাংশনে রাখা হয়েছে
- কোড সহজ ও সুন্দর হয়েছে
- বারবার ব্যবহারযোগ্যতা বেড়েছে
- মেইনটেন করা সহজ হয়েছে
✅ ২. মডুলার কোড কাকে বলে?
Modular code মানে হচ্ছে, পুরো প্রোগ্রামকে ছোট ছোট "module" বা অংশে ভাগ করে লেখা। প্রতিটি অংশ একটা নির্দিষ্ট কাজ করে।
📌 উদাহরণ:
ফাংশনের নাম | কাজ |
---|---|
getUserName() | ইউজারের নাম নেওয়া |
getTwoNumbers() | দুটি সংখ্যা ইনপুট নেওয়া |
add() | যোগফল বের করা |
display() | ফলাফল দেখানো |
এভাবে প্রতিটি কাজের জন্য আলাদা ফাংশন থাকলে:
✅ বুঝতে সহজ
✅ পুনঃব্যবহারযোগ্য (Reusable)
✅ টেস্ট/বাগ ফিক্স সহজ
✅ ভবিষ্যতে বড় সফটওয়্যারে সহজে এক্সটেন্ড করা যায়
✅ ৩. SOLID এর S – Single Responsibility Principle
S = Single Responsibility Principle (SRP)
👉 এটি বলে: "একটি ফাংশনের মাত্র একটি কাজ (responsibility) থাকা উচিত।"
🧠 কেন SRP গুরুত্বপূর্ণ?
- এতে কোড সুস্পষ্ট ও সহজবোধ্য হয়
- একটি ফাংশনে পরিবর্তন করলে অন্যগুলো ভাঙে না
- বাগ ফিক্সিং সহজ হয়
- টেস্টিং সহজ হয়
📌 উদাহরণ:
❌ খারাপ ডিজাইন (SRP ভঙ্গ করছে):
func handleEverything() {
// ইনপুট নেয়
// হিসাব করে
// প্রিন্ট করে
}
এই ফাংশন অনেক কাজ করছে একসাথে - যা SRP ভঙ্গ করে।
✅ ভালো ডিজাইন (SRP মেনে চলছে):
func getUserName() {}
func add() {}
func display() {}
এখানে প্রতিটি ফাংশন একটি মাত্র কাজ করছে - এটিই SRP।
🎯 ক্লাসের সারাংশ:
বিষয় | শেখা হয়েছে |
---|---|
ফাংশনের প্রয়োজনীয়তা | ✅ |
কোড মডুলার করার উপায় | ✅ |
SOLID এর 'S' – Single Responsibility | ✅ উদাহরণসহ |
🧠 সমস্যা:
- একই
main()
ফাংশনে সবকিছু একত্রে থাকায় কোডটি বড় ও জটিল হয়ে গেছে - পুনরায় ব্যবহারযোগ্যতা নেই
- মেইনটেন করা কঠিন
✅ ফাংশন ব্যবহার করার পরে
একই কাজকে ফাংশনের মাধ্যমে ভাগ করে সহজ করা হয়েছে:
package main
import "fmt"
func printWelcomeMessage() {
fmt.Println("Welcome to the application")
}
func getUserName() string {
var name string
fmt.Println("Enter your name - ")
fmt.Scanln(&name)
return name
}
func getTowNumbers() (int, int) {
var num1 int
var num2 int
fmt.Println("Enter first number - ")
fmt.Scanln(&num1)
fmt.Println("Enter second number - ")
fmt.Scanln(&num2)-
return num1, num2
}
func add(num1 int, num2 int) int {
sum := num1 + num2
return sum
}
func display(name string, sum int) {
fmt.Println("Hello, ", name)
fmt.Println("Summation = ", sum)
}
func printGoodByeMessage() {
fmt.Println("Thank you for using the application")
fmt.Println("Goodbye")
}
func main() {
printWelcomeMessage()
name := getUserName()
num1, num2 := getTowNumbers()
sum := add(num1, num2)
display(name, sum)
printGoodByeMessage()
}
✅ সুবিধা:
- প্রতিটি কাজ আলাদা ফাংশনে রাখা হয়েছে
- কোড সহজ ও সুন্দর হয়েছে
- বারবার ব্যবহারযোগ্যতা বেড়েছে
- মেইনটেন করা সহজ হয়েছে
✅ ২. মডুলার কোড কাকে বলে?
Modular code মানে হচ্ছে, পুরো প্রোগ্রামকে ছোট ছোট "module" বা অংশে ভাগ করে লেখা। প্রতিটি অংশ একটা নির্দিষ্ট কাজ করে।
📌 উদাহরণ:
ফাংশনের নাম | কাজ |
---|---|
getUserName() | ইউজারের নাম নেওয়া |
getTwoNumbers() | দুটি সংখ্যা ইনপুট নেওয়া |
add() | যোগফল বের করা |
display() | ফলাফল দেখানো |
এভাবে প্রতিটি কাজের জন্য আলাদা ফাংশন থাকলে:
✅ বুঝতে সহজ
✅ পুনঃব্যবহারযোগ্য (Reusable)
✅ টেস্ট/বাগ ফিক্স সহজ
✅ ভবিষ্যতে বড় সফটওয়্যারে সহজে এক্সটেন্ড করা যায়
✅ ৩. SOLID এর S – Single Responsibility Principle
S = Single Responsibility Principle (SRP)
👉 এটি বলে: "একটি ফাংশনের মাত্র একটি কাজ (responsibility) থাকা উচিত।"
🧠 কেন SRP গুরুত্বপূর্ণ?
- এতে কোড সুস্পষ্ট ও সহজবোধ্য হয়
- একটি ফাংশনে পরিবর্তন করলে অন্যগুলো ভাঙে না
- বাগ ফিক্সিং সহজ হয়
- টেস্টিং সহজ হয়
📌 উদাহরণ:
❌ খারাপ ডিজাইন (SRP ভঙ্গ করছে):
func handleEverything() {
// ইনপুট নেয়
// হিসাব করে
// প্রিন্ট করে
}
এই ফাংশন অনেক কাজ করছে একসাথে - যা SRP ভঙ্গ করে।
✅ ভালো ডিজাইন (SRP মেনে চলছে):
func getUserName() {}
func getTwoNumbers()
func add() {}
func display() {}
এখানে প্রতিটি ফাংশন একটি মাত্র কাজ করছে - এটিই SRP।
[Author : @shahriar-em0n Date: 2025-06-13 Category: interview-qa/class-wise ]
🧱 Class 14: What is Scope
Scope বলতে code এর part বুঝায় যেখানে একটি নির্দিষ্ট variable কে access করা যাবে।
📘 ক্লাসে ব্যবহৃত কোড
package main
import "fmt"
var (
a = 20
b = 30
)
func add(x int, y int) {
z := x + y
fmt.Println(z)
}
func main() {
p := 30
q := 40
add(p, q)
add(a, b)
add(a, p)
add(b, z) // ❌ error!
}
✨ Code Explain
var (
a = 20
b = 30
)
🔸 RAM এ একটা জায়গায় এ variable গুলো রাখা হয় যেটাকে global memory বলা হয়।
🔸 a
এবং b
এই দুইটা RAM এর global scope এ declare করা হয়েছে।
🔸 যেকোন ফাংশনের ভেতর থেকে এগুলোকে ব্যবহার করা যাবে।
🧠 যেসব ভ্যারিয়েবল
main()
বা অন্য কোনো ফাংশনের বাইরে delare করা হয় - সেগুলো global.
👉 main()
এবং add()
function ও RAM এর global scope এ থাকে (বুঝার সুবিধার্থে)।
💡 শুরুতে RAM এ যা থাকে
RAM
+------------------------------------------+
| 20 | 30 | ---- |---- | | | | | |
+------------------------------------------+
a b add() main()
global
Go প্রোগ্রামে
main()
ফাংশন না থাকলে, প্রোগ্রাম চলবে না।main()
হচ্ছে execution শুরু করার জায়গা; ওটা ছাড়া Go বুঝতে পারে না কোথা থেকে শুরু করবে।
main()
Execution
func main() {
p := 30
q := 40
add(p, q)
add(a, b)
add(a, p)
add(b, z)
}
🔸RAM এ main()
এর জন্য আলাদা জায়গা দখল করে
🔸p ও q হলো main()
এর local variable
🔸এগুলো main()
এর বাইরে থেকে ব্যবহার করা যাবে না
RAM
+------------------------------------------+
| 30 | 40 | | | | | | | | | | | |
+------------------------------------------+
p q
main()
main()
এadd()
function না থাকায়add()
কে global এ খুঁজে
add()
Execution
func add(x int, y int) {
z := x + y
fmt.Println(z)
}
🔸 RAM এ add()
এর জন্য আলাদা জায়গা নেয়
🔸 x
, y
& z
হল add()
এর local variable
🔸 x
এবং y
হল add()
function এর parameter
🔸add()
function শেষ হলে RAM থেকে এদের মুছে ফেলা হয়।
RAM
+------------------------------------------+
| 30 | 40 | 70 | | | | | | | | | |
+------------------------------------------+
x y z
add()
❌ যদি স্কোপ ভুলে যাও
func add(x int, y int) {
z := x + q
fmt.Println(z)
}
🔸q
variable add()
এর local scope এ নেই
🔸q
-> main()
এর local variable হওয়ায় global scope এ পাওয়া যাবে না
Scope এর বাইরের variable use করলে
undefined
compilation error দিবে।
Output:
# command-line-arguments
./main.go:11:11: undefined: q
🧠 Scope Rule
কোথায় declare হয়েছে | কোথা থেকে accessible |
---|---|
ফাংশনের বাইরে (global) | সব ফাংশন থেকে access করা যায় ✅ |
ফাংশনের ভিতরে (local) | শুধু সেই ফাংশনের ভিতরেই accessible ✅ |
অন্য ফাংশনের ভিতর | বাইরে থেকে access করা যায় না ❌ |
[Author : @nazma98 Date: 2025-06-13 Category: interview-qa/class-wise ]
Class 15 - Local Scope and Block
🧠 Scope types
Scope ৩ টাইপের।
- Global scope
- Local scope
- Package scope
1️⃣ Global Scope
🔹 যে variable বা function, main()
এর বাইরে declare করা হয়
🔹 সব ফাংশন থেকে access করা যায়
var x = 100
func main() {
fmt.Println(x)
}
এখানে x
একটি global variable, তাই main()
function একে access করতে পারছে।
🧱 Block Scope
Go তে যেকোনো {}
curly brace কে Block
বলে।
Block এর ভিতরে যদি variable declare করা হয়, তাহলে সেটা সেই block এর local scope এ পরে এবং একে ওই Block এর local variable বলে।
✨ Code Example
func main() {
x := 18
if x >= 18 {
p := 10
fmt.Println("I'm matured boy")
fmt.Println("I've ", p, " girlfriends")
}
}
✨ Code Explanation
🔹 main() ফাংশন শুরু
func main() {
x := 18
- এখানে
x
variable টিmain()
ফাংশনের ভিতরে declare করা হয়েছে। x
এর scope পুরোmain()
ফাংশনের ভিতর - একে বলে local variable tomain()
🔹 if Block
if x >= 18 {
p := 10
fmt.Println("I'm matured boy")
fmt.Println("I've ", p, " girlfriends")
}
if
block শুরু হয়েছে{
দিয়ে এবং শেষ হয়েছে}
দিয়ে - এটি হলো একটা Block।- block এর ভিতরে
p := 10
- তাইp
এর scope কেবলif
block এর ভিতরেই সীমাবদ্ধ। p
কেmain()
ফাংশনের বাইরে বাif
block এর বাইরে ব্যবহার করা যাবে না
🧠 RAM Visualization (Scope অনুযায়ী)
RAM
+------------------------------+
| x = 18 ← main() scope |
+------------------------------+
⬇ if block executed
+------------------------------+
| x = 18 |
| p = 10 ← if block scope |
+------------------------------+
⛔ if block শেষ হওয়ার পর
+------------------------------+
| x = 18 |
| p = ❌ (not accessible) |
+------------------------------+
🚫 Scope এর বাইরে variable access
📄Code Example - 01
func main() {
x := 18
if x >= 18 {
p := 10
fmt.Println("I'm matured boy")
fmt.Println("I've ", q, " girlfriends")
}
}
💬 Code Explanation
🔹main()
ফাংশন
func main() {
x := 18
x
হল একটি local variable to main()
তাই main()
ফাংশনের যেকোনো জায়গা থেকে access করা যাবে।
🔹 if block
p := 10
if
block এর ভেতরে declare করা হয়েছে, তাই block scope অনুযায়ী p
শুধু if
block এর ভিতরে accessible
fmt.Println("I've ", q, " girlfriends")
- এখানে
q
কোথাও declare করা হয়নি - Go এখন
main()
বা global scope এ খুঁজে দেখবে - কিন্তু সেখানে নেই - তাই Go কম্পাইলার
"undefined: q" error
দিবে
🧠 RAM Visualization (Scope অনুযায়ী)
RAM (Execution Time)
+-------------------------------+
| x = 18 ← main() scope |
+-------------------------------+
↓ if block executed
+-------------------------------+
| x = 18 |
| p = 10 ← if block scope |
| q = ??? ❌ (not found!) |
+-------------------------------+
📄 Code Example - 02
func main() {
x := 18
if x >= 18 {
p := 10
fmt.Println("I'm matured boy")
fmt.Println("I've ", p, " girlfriends")
}
fmt.Println("I've ", p, " girlfriends")
}
🧱 Scope বিশ্লেষণ
🔹 x := 18
main()
ফাংশনের ভিতরে declare করা হয়েছে → তাইx
এর scope হলো পুরোmain()
ফাংশনের ভিতর।
🔹 if x >= 18 { ... }
- এই block এর ভিতরে
p := 10
declare করা হয়েছে। - তাই
p
এর scope শুধুমাত্র এইif
block এর ভিতরে।
🔹 fmt.Println("I've ", p, " girlfriends")
- এখানে
p
কে use করা হয়েছে তার নিজের scope এর মধ্যেই
🔹 if block এর বাহিরের fmt.Println("I've ", p, " girlfriends")
p
,if
block এর ভিতরে declare হয়েছে → তাই বাইরে access করা যাবে না- ❌ এখানে
p
এর scope এর বাইরে চলে গেছে - তাই Go কম্পাইলার error দিবে:
undefined: p
💾 RAM Visualization (Scope অনুযায়ী)
RAM
+-----------------------------+
| x = 18 ← main scope |
+-----------------------------+
⬇ if block শুরু হলে
+-----------------------------+
| x = 18 |
| p = 10 ← if block only |
+-----------------------------+
⬇ if block শেষ
+-----------------------------+
| x = 18 |
| p = ❌ (Not Found!) |
+-----------------------------+
🧠 Block Scope এর মূল পয়েন্টগুলো
✅ Block আসলে memory তে নতুন জায়গা দখল করে।
- প্রতিবার কোনো block (যেমন:
if
, for
,switch
, function
) চালু হলে RAM এ সেই block এর জন্য অস্থায়ী জায়গা (temporary memory space) তৈরি হয়।
✅ Block এর ভিতরে declare করা variable বাইরে থেকে access করা যাবে না।
- Variable শুধুমাত্র সেই block এর local scope এর ভিতরে কাজ করে।
✅ Block শেষ হলেই সেই variable RAM থেকে মুছে যায় বা আর access করা যায় না।
- কারণ Go এর compiler বুঝে - variable টি তার scope এর বাইরে চলে গেছে।
[Author: @nazma98 Date: 2025-06-14 Category: interview-qa/class-wise ]
🧠 Class 16: GoLang package scope
১. Package কী?
Package হলো GoLang কোড গুছিয়ে রাখার একটি পদ্ধতি। একটি Package অনেকগুলো ফাইল থাকতে পারে, এবং সবগুলোর package
নাম একই হলে তারা একে অপরের কোড ব্যবহার করতে পারে।
✅ নিয়ম:
- একই ফোল্ডারে সব
.go
ফাইলেরpackage
নাম এক হওয়া উচিত। package main
হলে সেটি রানযোগ্য প্রোগ্রাম।- অন্য প্যাকেজ যেমন
package mathlib
→ লাইব্রেরি বা ইউটিলিটি হিসেবে ব্যবহৃত হয়।
২. Scope এবং Export কী?
📌 কোন জায়গা থেকে কোন ফাংশন বা ভেরিয়েবল অ্যাক্সেস করা যাবে।
- যদি function নাম ছোট হাতের অক্ষরে শুরু হয় (যেমন
add
), তাহলে এটি শুধুমাত্র সেই Packageর ভিতরেই ব্যবহার করা যাবে। - যদি বড় হাতের অক্ষরে শুরু হয় (যেমন
Add
), তাহলে সেটি এক্সপোর্টেড হয় এবং অন্য প্যাকেজ থেকেও ব্যবহার করা যায়।
৩. কোড উদাহরণ
📁 add.go
package main
import "fmt"
func add(n1, n2 int) {
res := n1 + n2
fmt.Println(res)
}
📌 add()
function নাম ছোট হাতের অক্ষরে, তাই এটা শুধু main
Packageর ভিতরেই কাজ করবে।
📁 main.go
package main
var (
a = 20
b = 30
)
func main() {
add(4,7)
}
📌 এখানে add()
কল করা হয়েছে কারণ add.go
ফাইল একই Package আছে (package main)।
👉 রান করতে হবে:
go run main.go add.go
📁 কাস্টম প্যাকেজ mathlib/math.go
package mathlib
import "fmt"
func Add(x int, y int) {
z := x + y
fmt.Println(z)
}
📌 এবার Add()
function বড় হাতের অক্ষরে শুরু → Exported
📌 mathlib
নামে প্যাকেজ → একে অন্য ফোল্ডারে রাখতে হবে (যেমন: mathlib/
)
📁 main.go
(পরিবর্তিত ভার্সন)
package main
import (
"fmt"
"example.com/mathlib"
)
var (
a = 20
b = 30
)
func main() {
fmt.Println("Showing Custom Package")
mathlib.Add(4,7)
}
📌 এখানে mathlib.Add()
ব্যবহার করা হয়েছে কারণ Add()
এক্সপোর্টেড এবং আমরা import
করেছি।
৪. মডিউল ব্যবস্থাপনা
✅ মডিউল শুরু করতে:
go mod init example.com/mathlib
৫. Key Concepts
বিষয় | ব্যাখ্যা |
---|---|
একই ফোল্ডার = একই প্যাকেজ | main.go , add.go → package main |
কাস্টম Package আলাদা ফোল্ডার | যেমন mathlib/math.go |
রান করতে হলে সব ফাইল দিতে হবে | go run main.go add.go |
বড় হাতের ফাংশন নাম = এক্সপোর্টেড | অন্য প্যাকেজ থেকে ব্যবহারযোগ্য |
go mod init দিয়ে মডিউল শুরু হয় | কাস্টম প্যাকেজ ব্যবহারে দরকার |
🧠 সারাংশ:
- প্যাকেজ ব্যবহারে কোড পরিষ্কার ও পুনঃব্যবহারযোগ্য হয়।
- স্কোপ বুঝে কোড গঠন করলে সমস্যা হয় না।
- এক্সপোর্টেড ফাংশন ও মডিউল ব্যবস্থাপনা জানলে বড় প্রজেক্টেও কাজ সহজ হয়।
[Author: @ifrunruhin12 @shahriar-em0n Date: 2025-05-01 Category: interview-qa/class-wise ]
🧠 Class 17: Scope with another boring example
🧑💻 Code Example :
package main
import "fmt"
var (
a = 10
b = 20
)
func printNum(num int) {
fmt.Println(num)
}
func add(x int, y int) {
res := x + y
printNum(res)
}
func main() {
add(a, b)
}
🧠 মূল ধারণাসমূহ
✅ অর্ডার ম্যাটার করে না (প্যাকেজ-লেভেলের জন্য)
Go তে ফাংশন এবং গ্লোবাল ভ্যারিয়েবলগুলোর অর্ডার (ক্রম) গুরুত্বপূর্ণ নয়। মানে main()
ফাংশনের পরেও যদি অন্য ফাংশন বা ভ্যারিয়েবল ডিক্লেয়ার করা হয়, Go ঠিকই সব চিনে নেয় এবং কম্পাইল করে।
🤓 Go ≠ ফাংশনাল প্রোগ্রামিং প্যারাডাইম
Go কিছু দারুণ ফিচার ধার করেছে ফাংশনাল ল্যাঙ্গুয়েজ থেকে (যেমন: ফার্স্ট-ক্লাস ফাংশন, ক্লোজার ইত্যাদি), কিন্তু Go নিজে ফাংশনাল প্রোগ্রামিং ল্যাঙ্গুয়েজ নয়।
⚖️ তাহলে Go কোন প্যারাডাইমে পড়ে?
Go হলো একাধিক প্যারাডাইম সাপোর্ট করে এমন ভাষা, তবে এর মূল স্টাইল হচ্ছে imperative এবং procedural। এটি ক্লাসিক OOP-এর বদলে struct-based composition কে গুরুত্ব দেয়।
এটি ডিজাইন করা হয়েছে যাতে ভাষাটি হয়:
- সহজ
- ভবিষ্যৎ অনুমানযোগ্য (Predictable)
- সহজে পড়া যায় এমন (Readable)
তুমি চাইলে functional-এর মতো স্টাইলে কোড লিখতে পারো, কিন্তু Go কে ডিজাইন করা হয়নি অনেক জটিল functional abstraction-এর জন্য।
[Author: @ifrunruhin12 @shahriar-em0n Date: 2025-05-01 Category: interview-qa/class-wise ]
💡 ইন্টারভিউ প্রশ্ন: Go-তে variable shadowing
🧪 Code Example :
package main
import "fmt"
var a = 10
func main() {
age := 30
if age > 18 {
a := 47 // শুধু এই if ব্লকের ভিতরে গ্লোবাল `a` কে shadow করে
fmt.Println(a) // ➜ 47
}
fmt.Println(a) // ➜ 10 (গ্লোবাল `a` প্রিন্ট করে)
}
📌 গুরুত্বপূর্ণ বিষয়:
- ভেরিয়েবল শ্যাডোয়িং হয় যখন লোকাল ভেরিয়েবলের নাম বাইরের স্কোপের ভেরিয়েবলের নামের সঙ্গে মিলে যায়।
- Go কোন Error দিবে না এটি শুধুমাত্র বর্তমান স্কোপে থাকা সবচেয়ে ভিতরের ভেরিয়েবলটি ব্যবহার করবে।
- Global
a
অপরিবর্তিত থাকে এবং if ব্লকের বাইরে প্রিন্ট হয়।
🧠 Memory ও stack animation
⏱ প্রোগ্রাম শুরু
📦 Data segment:
┌─────────────┐
│ global a=10 │ ◄── প্রোগ্রাম শেষ হওয়া পর্যন্ত থাকে
└─────────────┘
🚀 main() কল হয়
📚 Stack:
┌────────────────────────────┐
│ 🧩 main() stack frame │
│ └── age = 30 │
└────────────────────────────┘
✅ if ব্লকে প্রবেশ (কারণ age > 18 সত্য)
🧱 নতুন ব্লক স্কোপ শুরু
📚 Stack:
┌────────────────────────────┐
│ 🧩 main() stack frame │
│ └── age = 30 │
│ 🔸 a (shadow করা) = 47 | ◄── global `a` কে shadow করে
└────────────────────────────┘
🖨️ fmt.Println(a) ➜ output: 47 ✅
🔚 if ব্লক শেষ, shadow করা a
ডিলিট হয়
📚 Stack:
┌────────────────────────────┐
│ 🧩 main() stack frame │
│ └── age = 30 │
└────────────────────────────┘
🖨️ fmt.Println(a) ➜ output: 10 ✅ (global a
)
🔚 main() শেষ, stack clear
📚 Stack:
(empty)
🧼 প্রোগ্রাম শেষ
📌 ভিজ্যুয়াল সারাংশ
- গ্লোবাল variable (যেমন
a = 10
) ডাটা সেগমেন্টে থাকে। - লোকাল variable (যেমন
age
বা shadow করেa
) স্ট্যাকে থাকে। - নতুন scope (যেমন if, for, function block) এ ঢুকলে নতুন variable স্ট্যাকে পুশ হয়।
- ব্লক শেষ হলে shadow করা variable স্ট্যাক থেকে মুছে যায়।
- প্রোগ্রাম শেষ হলে স্ট্যাক ক্লিয়ার হয়, কিন্তু ডাটা সেগমেন্ট পুরো সময় জীবিত থাকে।
[Author: @ifrunruhin12 @shahriar-em0n Date: 2025-05-01 Category: interview-qa/class-wise ]
🧠 Class 19: Function Types in Go
1️⃣ Standard Function (নির্ধারিত function)
একটি সাধারণভাবে নামযুক্ত function যা func
কীওয়ার্ড দিয়ে তৈরি করা হয়।
func add() {
fmt.Println("Hello!")
}
2️⃣ Anonymous Function (নামহীন function)
এই ফাংশনের কোনো নাম থাকে না। একে ইনলাইন বা তৎক্ষণাৎ ব্যবহার করা যায়।
func() {
fmt.Println("I have no name!")
}()
3️⃣ Function Expression (ভেরিয়েবলে function সংরক্ষণ)
ফাংশনটিকে একটি ভেরিয়েবলে সংরক্ষণ করে পরে ব্যবহার করা হয়।
hello := func() {
fmt.Println("Hi there!")
}
hello()
4️⃣ Higher-Order Function / First-Class Function
যে function অন্য ফাংশনকে প্যারামিটার হিসেবে গ্রহণ করে অথবা function রিটার্ন করে।
func operate(a int, b int, fn func(int, int) int) int {
return fn(a, b)
}
5️⃣ Callback Function (পুনরায় কল করা হয় এমন function)
একটি function যা আরেকটি ফাংশনে প্যারামিটার হিসেবে পাঠানো হয় এবং নির্দিষ্ট সময়ে কল করা হয়।
func process(callback func()) {
callback()
}
6️⃣ Variadic Function (বহু সংখ্যক প্যারামিটার গ্রহণ করে)
একটি function যা পরিবর্তনশীল সংখ্যক আর্গুমেন্ট গ্রহণ করতে পারে।
func sum(nums ...int) {
total := 0
for _, num := range nums {
total += num
}
fmt.Println(total)
}
7️⃣ Init Function (Go নিজে থেকে কল করে)
Go প্রোগ্রাম রান করার সময় main()
এর আগেই init()
ফাংশনটি কল হয়। এটি ম্যানুয়ালি কল করা যায় না।
func init() {
fmt.Println("Initializing...")
}
8️⃣ Closure (বাইরের স্কোপের ভেরিয়েবল বন্ধ করে ফেলে)
একটি function যা বাইরের স্কোপের ভেরিয়েবল "বন্ধ" বা retain করে রাখে।
func outer() func() int {
count := 0
return func() int {
count++
return count
}
}
9️⃣ Defer Function (শেষে কল হয় Stack এর Last In First Out নিয়মে)
defer
কীওয়ার্ড ব্যবহারে ফাংশনটি পরে কল হয়, সাধারণত function শেষ হওয়ার আগে।
func test() {
defer fmt.Println("Three")
defer fmt.Println("Two")
fmt.Println("One")
}
🟢 output:
One
Two
Three
🔟 Receiver Function / Method (struct এর সাথে যুক্ত function)
Go তে struct এর সাথে method সংযুক্ত করা যায়।
type Person struct {
name string
}
func (p Person) add() {
fmt.Println("Hello", p.name)
}
1️⃣1️⃣ IIFE - Immediately Invoked Function Expression
একটি function যা একসাথে define এবং invoke করা হয়।
func(msg string) {
fmt.Println(msg)
}("IIFE Example")
[Author: @ifrunruhin12 @shahriar-em0n Date: 2025-05-01 Category: interview-qa/class-wise ]
🧠 Class 20: Init Function
📺 Video Topic: init()
Function in Go
🔤 Code Written in This Class
✅ Example 1
package main
import "fmt"
func main() {
fmt.Println("Hello Init Function!")
}
func init() {
fmt.Println("I am the function that is executed first")
}
✅ Example 2
package main
import "fmt"
var a = 10
func main() {
fmt.Println(a)
}
func init() {
fmt.Println(a)
a = 20
}
🔍 Key Concepts
init()
একটি বিশেষ Go function যাmain()
এর আগে automatically run হয় ।- একাধিক ফাইল এবং প্যাকেজে একাধিক
init()
থাকতে পারে। চালানোর ক্রম:- Dependency packages আগে
- তারপর ফাইল অর্ডার অনুযায়ী (উপরে থেকে নিচে)
init()
ম্যানুয়ালি কল করা যায় না। এটি প্রোগ্রাম শুরু হওয়ার আগেই চলে।
🧠 CLI Memory & Execution Visualization (Example 1)
🛠 Compile Time: Go detects init()
Found init() in main package ✅
----------- EXECUTION BEGINS -----------
🧠 Data Segment:
(none)
📚 Stack:
┌────────────────────┐
│ 🧩 init() │
└────────────────────┘
🖨️ Output:
"I am the function that is executed first"
👋 init() returns
📚 Stack:
┌────────────────────┐
│ 🧩 main() │
└────────────────────┘
🖨️ Output:
"Hello Init Function!"
✅ Program ends gracefully
🔍 CLI Visualization: Execution & Memory Layout (Example 2)
=========== Program Compilation ===========
Found global variable: a = 10
Found init() ✅
Found main() ✅
=========== Execution Begins ==============
🧠 Data Segment (Globals):
a = 10 ← initialized before anything runs
📚 Stack Frame:
┌────────────┐
│ init() │
└────────────┘
🔁 init() runs
→ Prints: 10
→ Updates a = 20
Stack after init():
(returns to runtime)
📚 Stack Frame:
┌────────────┐
│ main() │
└────────────┘
🔁 main() runs
→ Prints: 20
=========== Execution Ends ================
📌 Summary
- Global variable
a
প্রোগ্রাম চলার আগেই initialized হয়। init()
প্রথমে execute হয়:a = 10
পড়েa = 20
করে আপডেট করে
main()
updated value দেখায়:20
এটি একটি ক্লাসিক উদাহরণ, যেখানে
init()
মূল প্রোগ্রাম চলার আগে runtime environment প্রস্তুত করে।
⚡ Quick Recap
init()
সবসময়main()
এর আগে চলে, এমনকি যদি কোডে পরে লেখা থাকে।- এটি config, database connection, default value ইত্যাদি initialize করার জন্য ব্যবহার করা হয়।
- একটি Go ফাইলে একটাই
main()
থাকতে পারে, কিন্তু একাধিকinit()
থাকতে পারে।
Init is like the secret backstage crew. You don’t see them during the show, but they’re the reason the lights come on.
[Author: @ifrunruhin12 @shahriar-em0n Date: 2025-05-01 Category: interview-qa/class-wise ]
Class 21 – expression, anonymous function ও IIFE - in go
🎥 ভিডিও নাম: anonymous function, expression ও IIFE
🔤 Code Written in This Class
// anonymous function
// IIFE - ইমিডিয়েটলি ইনভোকড function expression
package main
import "fmt"
func main() {
// anonymous function
func(a int, b int) {
c := a + b
fmt.Println(c)
}(5, 7) // IIFE
}
func init() {
fmt.Println("আমি সবার আগে কল হব")
}
🧠 মূল ধারণাসমূহ
Go-তে Expression (expression)
expression হলো যেকোনো code snippet যা কোনো মান (value) রিটার্ন করে।
example:
a + b // একটি expression
func(x, y){} // একটি function expression
expression মান হিসেবে ব্যবহার, pass অথবা সাথে সাথেই execute করা যায়।
anonymous function
anonymous function হলো নামবিহীন function।
func(a, b int) int {
return a + b
}
✅ এটি ভ্যারিয়েবল হিসেবে সংরক্ষণ, আর্গুমেন্ট হিসেবে pass বা সাথে সাথেই কল করা যায়।
⚡ IIFE (Immediately Invoked Function Expression)
IIFE হলো এমন একটি anonymous function যেটি ডিক্লেয়ার করার সাথেসাথে execute হয়।
func(a int, b int) {
// কাজ
}(5, 7)
ব্যবহার: ছোট লজিক ব্লক তাৎক্ষণিক চালানোর জন্য উপযোগী, নতুন নাম না দিয়েই।
🖥️ CLI- execution vizualization
=========== compilation ধাপ =============
init() function খুঁজে পাওয়া গেছে ✅
main() function খুঁজে পাওয়া গেছে ✅
=========== এক্সিকিউশন ধাপ =============
🔁 init() প্রথমে চলে
→ আউটপুট: আমি সবার আগে কল হব
🧠 ডেটা সেগমেন্ট:
(কোনো গ্লোবাল ভ্যারিয়েবল নেই)
📚 stack frame:
┌─────────────────────┐
│ main() │
│ ┌─────────────────┐ │
│ │ anonymous function │ │
│ └─────────────────┘ │
└─────────────────────┘
main() একটি IIFE কল করে:
→ 5 এবং 7 pass করে
→ ভিতরে: c := 5 + 7 = 12
→ output: 12
=========== execution সম্পূর্ণ ============
🧵 TL;DR (সংক্ষেপে)
- [] expression- মান রিটার্ন করে, এসাইন বা execute করা যায়।
- [] anonymous function- দ্রুত লজিক ব্লক চালাতে ব্যবহৃত হয়।
- [] IIFE- ডিফাইন এবং execute একসাথে — একবারের কাজের জন্য দারুন!
[Author: @ifrunruhin12 @shahriar-em0n Date: 2025-05-01 Category: interview-qa/class-wise ]
📘 CLass 22 – Go Function Expression & Shadowing
🎥 ভিডিও নাম: Function Expression Example
✅ Example 1:
package main
import "fmt"
// গ্লোবাল ফাংশন এক্সপ্রেশন
var add = func(x, y int) {
fmt.Println(x + y)
}
func main() {
add(4, 7) // গ্লোবাল `add` কল হচ্ছে
// লোকাল ভেরিয়েবলে ফাংশন এক্সপ্রেশন অ্যাসাইন করা
add := func(a int, b int) {
c := a + b
fmt.Println(c) কোড ২
}
add(2, 3) // এখন লোকাল `add` কল হচ্ছে
}
func init() {
fmt.Println("আমি প্রথমে কল হব")
🧠 মূল ধারণাসমূহ
🔧 Function Expression
যখন কোনো ফাংশনকে একটি ভেরিয়েবলে সংরক্ষণ করা হয়। এর মাধ্যমে আমরা —
- logic একটি ভেরিয়েবলে রাখতে পারি
- ফাংশনকে ফার্স্ট-ক্লাস সিটিজেন হিসেবে ব্যবহার করতে পারি
- inline বা anonymous ফাংশন তৈরি করতে পারি
উদাহরণ:
add := func(a int, b int) {
fmt.Println(a + b)
}
🧱 Shadowing
যখন একটি ছোট স্কোপে (লোকাল স্কোপে) থাকা ভেরিয়েবলের নাম বড় স্কোপে থাকা একই নামের ভেরিয়েবলকে ঢেকে ফেলে বা “শ্যাডো” করে।
add := func(a int, b int) {...}
এই add
লোকাল স্কোপে গ্লোবাল add
কে ঢেকে দেয়।
🖥️ CLI- execution vizualization
========== কম্পাইলেশন ফেজ ==========
✔ init() পাওয়া গেছে
✔ main() পাওয়া গেছে
✔ গ্লোবাল `add` ফাংশন অ্যাসাইন করা হয়েছে
========== এক্সিকিউশন শুরু ==========
init():
→ প্রিন্ট করে: আমি প্রথমে কল হব
main():
→ গ্লোবাল `add(4, 7)` → প্রিন্ট: 11
main() এর ভিতরের লোকাল স্কোপ:
┌──────── Stack Frame ───────┐
│ main() │
│ ┌──────────────┐ │
│ │ add (লোকাল) │────────┐ │
│ └──────────────┘ │ │
└─────────────────────────┘ │
(গ্লোবালটিকে ঢেকে দেয়) ◄───┘
→ লোকাল `add(2, 3)` → প্রিন্ট: 5
========== এক্সিকিউশন শেষ ==========
❌ Example 2: কম্পাইল হয় না
package main
import "fmt"
// গ্লোবাল ফাংশন এক্সপ্রেশন
var add = func(x, y int) {
fmt.Println(x + y)
}
func main() {
adder(4, 7) // ❌ ERROR: undefined: adder
adder := func(a int, b int) {
c := a + b
fmt.Println(c)
}
add(2, 3)
}
func init() {
fmt.Println("আমি প্রথমে কল হব")
}
❌ কেন এটা কাজ করে না?
এই লাইনটি:
adder(4, 7)
ডিক্লেয়ারেশনের উপরে আছে:
adder := func(a int, b int) { ... }
🛑 সমস্যা: Temporal Dead Zone
Go তে তুমি কোনো ভেরিয়েবলকে তার ডিক্লেয়ারেশনের আগে ব্যবহার করতে পারো না even একই ব্লকের মধ্যেও।
তাই adder
ব্যবহার করার সময়ে সেটি এখনো ডিক্লেয়ার হয়নি।
ভুল:
./main.go:10:2: undefined: adder
📚 TL;DR
ধারণা | অর্থ |
---|---|
Function Expression | একটি ভেরিয়েবলে সংরক্ষিত ফাংশন |
Anonymous Function | নামবিহীন ফাংশন |
Shadowing | লোকাল ভেরিয়েবল গ্লোবালটিকে ঢেকে দেয় |
Temporal Dead Zone | ডিক্লেয়ারেশনের আগে কোনো ভেরিয়েবল ব্যবহার করা যায় না |
IIFE vs Assignment | IIFE সাথে সাথে চলে; অ্যাসাইনমেন্ট পরে কল করতে হয় |
[Author: @ifrunruhin12 @shahriar-em0n Date: 2025-05-01 Category: interview-qa/class-wise ]
Class 23: Go-তে Functional Programming ধারণা
package main
import "fmt"
func add(a int, b int) { // Parameter: a and b
c := a + b
fmt.Println(c)
}
func main() {
add(2, 5) // 2 এবং 5 হলো argument
processOperation(4, 5, add)
sum := call() // function expression
sum(4, 7)
}
func processOperation(a int, b int, op func(p int, q int)) { // Higher order function
op(a, b)
}
func call() func(x int, y int) {
return add
}
🧠 মূল ধারণাসমূহ
১. Parameter বনাম Argument
- Parameter: ফাংশনের ভিতরে ডিফাইন করা ভেরিয়েবল (যেমন:
a int
,b int
inadd(a, b)
). - Argument: ফাংশন কল করার সময় যেসব মান পাঠানো হয় (যেমন:
add(2, 5)
এ2
এবং5
).
২. First Order Function
- এমন ফাংশন যেটি অন্য কোনো ফাংশন নেয় না বা ফেরত দেয় না।
- উদাহরণ:
- Named function:
func add(a, b int)
- Anonymous function:
func(a int, b int) { ... }
- IIFE:
func(a, b int) { ... }(5, 7)
- Function expression:
sum := func(a, b int) { ... }
- Named function:
৩. Higher Order Function
- এমন ফাংশন যা অন্য ফাংশন নেয়, ফেরত দেয়, অথবা দুটোই করে।
- উদাহরণ:
processOperation
একটি ফাংশন নেয়call()
একটি ফাংশন রিটার্ন করে
৪. Callback Function
- যেসব ফাংশন অন্য ফাংশনের ভিতরে পাঠানো হয় এবং পরে কল করা হয়।
- উদাহরণ:
processOperation(4, 5, add)
→ এখানেadd
হলো callback function
৫. First-Class Citizen (Function)
- Go-তে ফাংশনগুলো first-class citizen অর্থাৎ:
- ফাংশন ভেরিয়েবলে রাখা যায়
- আর্গুমেন্ট হিসেবে পাঠানো যায়
- অন্য ফাংশন থেকে রিটার্ন করা যায়
🧠 ধারণাগত প্রেক্ষাপট (Functional Programming Paradigm)
- Functional programming হলো গণিতের ফাংশনের মত হিসাব করা এবং mutable state পরিহার করা।
- অনুপ্রেরণা: গণিতের দুইটি লজিক ধারা —
- First Order Logic → বস্তু ও তার প্রপার্টি
- Higher Order Logic → ফাংশন এবং তার সম্পর্ক
- Haskell, Racket ইত্যাদি ভাষা ফাংশনাল প্রোগ্রামিং ভিত্তিক।
- Go এই ধারণা কিছুটা গ্রহণ করলেও মূলত এটি imperative/procedural ভাষা।
🖥️ CLI Visualization (Call Stack + Segment)
ডেটা সেগমেন্ট:
add
(গ্লোবাল ফাংশন)call
(ফাংশন রিটার্ন করে)processOperation
(স্টোর করা ফাংশন)
এক্সিকিউশন ফ্লো (স্ট্যাক ফ্রেম অনুযায়ী):
Call Stack:
┌──────────────────────────┐
│ main() │
│ ├── add(2, 5) │ => ৭ প্রিন্ট করে
│ ├── processOperation │
│ │ └── op(4, 5) → add │ => ৯ প্রিন্ট করে
│ ├── call() │ => add রিটার্ন করে
│ └── sum(4, 7) │ => ১১ প্রিন্ট করে
└──────────────────────────┘
সারসংক্ষেপ
- Go ফাংশনাল প্রোগ্রামিং এর অনেক ধারণা সমর্থন করে যেমন: first-class ও higher-order functions।
- ফাংশনগুলোকে ভেরিয়েবলের মত ব্যবহার করা যায় — কোড মডুলার ও পরিষ্কার হয়।
- Parameter বনাম Argument, First vs Higher Order Function, এবং Callback Function ভালোভাবে বোঝা clean এবং power-efficient কোড লেখার জন্য জরুরি।
[Author: @ifrunruhin12 @shahriar-em0n Date: 2025-05-01 Category: interview-qa/class-wise ]
ক্লাস ২৪ - Go Internal Memory (Code, Data, Stack, Heap)
🧠 আলোচনার বিষয়বস্তু
এই ক্লাসে একটি Go program
কম্পিউটারের মেমরিতে কীভাবে বিন্যস্ত থাকে সেটি নিয়ে বিস্তারিত আলোচনা করা হয়েছে। নিচে প্রয়োজনীয় ধারনাগুলো উল্লেখ করা হল :
- কোড সেগমেন্ট (Code Segment): কম্পাইল্ড ইন্সট্রাকশন (যেমন ফাংশন, কনস্ট্যান্ট ভ্যারিয়েবল ইত্যাদি যা পরবর্তীতে পরিবর্তন হওয়ার সুযোগ নেই) সংরক্ষণ করে।
- ডেটা সেগমেন্ট (Data Segment): প্রোগ্রামের স্ট্যাটিক (static) এবং গ্লোবাল (global) ভ্যারিয়েবল সংরক্ষণের জন্য ব্যবহৃত হয় (যেমন
var a = 10
)। - স্ট্যাক (Stack): ফাংশনের মধ্যে ব্যবহৃত লোকাল ভেরিয়েবলগুলো স্ট্যাকে সংরক্ষণ করা হয়। প্রতিটি ফাংশন কলের জন্য নতুন স্ট্যাকফ্রেম (Stack Frame) তৈরি করে।
- হিপ (Heap): ডাইনামিক মেমোরি অ্যালোকেশন (dynamic memory allocation) এর জন্য ব্যবহৃত হয় (এটি নিয়ে পরবর্তীতে বিস্তারিত আলোচনা করা হবে)।
- গারবেজ কালেক্টর (Garbage Collector): হিপ মেমোরি (heap memory) থেকে অব্যবহৃত বা অপ্রয়োজনীয় মেমোরি সরিয়ে মেমোরি ফাঁকা করে।
📜 ক্লাসের কোড:
package main
import "fmt"
var a = 10
func add(x, y int) {
z := x + y
fmt.Println(z)
}
func main() {
add(5,4)
add(a,3)
}
func init() {
fmt.Println("Hello")
}
🔍 কোড এক্সিকিউশন ফ্লো এবং মেমোরি লেআউট
┌────────────────────────────────────────────┐
│ Code Segment │
│--------------------------------------------│
│ Functions: init, main, add │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ Data Segment │
│--------------------------------------------│
│ Global Variable: a = 10 │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────┐
│ Stack │
│----------------------------│
│ main() Stack Frame │
│ - Calls add(5, 4) │
│ - x=5, y=4 │
│ - z=9 │
│ - Calls add(10, 3) │
│ - x=10, y=3 │
│ - z=13 │
└────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ Heap (Unused here) │
│ (Managed by the Garbage Collector) │
└────────────────────────────────────────────┘
⚙️ এক্সিকিউশন অর্ডার (Execution Order)
১। init()
একটি বিশেষ ফাংশন, যা main() ফাংশনের আগে স্বয়ংক্রিয়ভাবে (automatically) রান হয়। তাই এটি শুরুতে Hello
প্রিন্ট করবে।
Hello
২। এই পর্যায়ে main()
ফাংশন রান হবে এবং -[] add(5, 4)
ফাংশনকে কল করবে। ফলে প্রিন্ট হবে 9
9
এরপর -[] add(a, 3)
ফাংশনকে কল করবে যেখানে a
এর মান 10
ব্যবহার করবে (ডেটা সেগমেন্ট থেকে)। ফলে প্রিন্ট হবে 13
13
📌 মূল ধারনা পুনরালোচনা (Key Concepts Recap)
- কোড সেগমেন্ট | সব ফাংশন কম্পাইল হওয়ার পর যেখানে থাকে
- ডেটা সেগমেন্ট | গ্লোবাল ভেরিয়েবল সংরক্ষণ করে
- স্ট্যাক | ফাংশন রান হওয়ার সময় অস্থায়ী মেমরি (লোকাল ভেরিয়েবল, প্যারামিটার)
- হিপ | ডাইনামিক মেমরির জন্য
- গারবেজ কালেক্টর | হিপে থাকা মেমরি স্বয়ংক্রিয়ভাবে ম্যানেজ করে
init()
ফাংশন |Go
-তে বিশেষ ফাংশন —main()
এর আগে রান হয়
🧼 গারবেজ কালেক্টর সম্পর্কে উপলব্ধি: Go-এর গারবেজ কালেক্টর হিপে থেকে অব্যবহৃত মেমরি মুছে ফেলে। ছোট প্রোগ্রামে এটি তেমন বোঝা যায় না, তবে অ্যাপ বড় হলে এটি আপনার সেরা বন্ধু।
[Author: @ifrunruhin12, @nazma98 Date: 2025-05-01 - 2025-05-14 Category: interview-qa/class-wise ]
ক্লাস ২৫ - ইন্টারনাল মেমরি গভীর বিশ্লেষণ: কম্পাইলেশন ও এক্সিকিউশন পর্যায়
✨ আলোচিত বিষয়বস্তু
এই ক্লাসে একটি Go প্রোগ্রামের অভ্যন্তরীণ কার্যকলাপ নিয়ে আলোচনা করা হয়েছে, বিশেষ করে নিচের বিষয়গুলোর ওপর:
- কম্পাইলেশন পর্যায় (Compilation Phase)
- এক্সিকিউশন পর্যায় / রানটাইম (Execution Phase / Runtime)
- Go কীভাবে
go build
দিয়ে বাইনারি ফাইল তৈরি করে - সেই বাইনারি ফাইলে কী কী সংরক্ষিত হয় (ফাংশন, কনস্ট্যান্ট, গ্লোবাল ভেরিয়েবল ইত্যাদি)
- ফাংশন এক্সপ্রেশনের (যেমন,
add := func(...)
) মেমরিতে কীভাবে হ্যান্ডল করা হয়
👍 আলোচনার বিষয়বস্তু
ধারনা | ব্যাখ্যা |
---|---|
কম্পাইলেশন পর্যায় | সোর্স কোডকে বাইনারি এক্সিকিউটেবল এ পরিণত করে। এখনো কোনো কোড রান হয় না। |
এক্সিকিউশন পর্যায় | কম্পাইল হওয়া বাইনারি ফাইল রান করে, প্রথমে init() এবং তারপর main() থেকে শুরু হয়। |
কোড সেগমেন্ট | কম্পাইল হওয়া ফাংশন (main , call , anonymous add ) এবং কনস্ট্যান্ট (a ) এক্সিকিউটেবল ইন্সট্রাকশনের অংশ হিসেবে এখানে সংরক্ষিত থাকে। |
ডেটা সেগমেন্ট | গ্লোবাল ভেরিয়েবল (যেমন, p ) এখানে সংরক্ষিত হয়। |
ফাংশন এক্সপ্রেশন | রানটাইমে ফাংশন অবজেক্ট হিসেবে বিবেচিত হয় এবং কোড সেগমেন্টে সংরক্ষিত থাকে। |
📋 ক্লাস ২৫ এর কোড:
package main
import "fmt"
const a = 10 // constant
var p = 100
func call() {
add := func(x int, y int) {
z := x + y
fmt.Println(z)
}
add(5, 6)
add(p, a)
}
func main() {
call()
fmt.Println(a)
}
func init() {
fmt.Println("Hello")
}
🔄 কম্পাইলেশন পর্যায়ের ভিজ্যুয়ালাইজেশন
go build main.go
- পার্সার/কম্পাইলার: সিনট্যাক্স, স্কোপ এবং ডিপেন্ডেন্সি যাচাই করে।
- সংরক্ষণ করে:
- কনস্ট্যান্ট: a = 10
- গ্লোবাল ভেরিয়েবল: p = 100
- ফাংশন:
init
,main
,call
, এবংcall
এর ভেতরের anonymousadd
ফাংশন - প্রয়োজনীয় মেশিন কোড + মেটাডাটার
বাইনারি
জেনারেট করে
বাইনারি ফাইলে থাকে:
- কোড সেগমেন্ট: কনস্ট্যান্ট
a
,main
,call
, anonymous ফাংশন - ডেটা সেগমেন্ট: ভ্যারিয়েবল
p
- এখানে কোনো এক্সিকিউশন হয় না।
⏱ এক্সিকিউশন পর্যায়ের ভিজ্যুয়ালাইজেশন
১. init() => "Hello"
২. main() => call() ফাংশনকে কল করে
৩. call() => add() ফাংশনকে ডিক্লেয়ার এবং কল করে
- add(5, 6) => 11
- add(100, 10) => 110
৪. fmt.Println(a) => 10
🧠 মেমরি লেআউট
┌─────────────────────────────┐
│ Code Segment │
│-----------------------------│
│ const a = 10 |
| main, call, init, add-func │
└─────────────────────────────┘
↓
┌─────────────────────────────┐
│ Data Segment │
│-----------------------------│
│ var p = 100 │
└─────────────────────────────┘
↓
┌─────────────────────────────┐
│ Stack │
│-----------------------------│
│ call() frame → add func │
│ x=5,y=6,z=11 │
│ x=100,y=10,z=110 │
└─────────────────────────────┘
🔹সারাংশ
- একটি Go প্রোগ্রাম দুইটি পর্যায়ে রান হয়: কম্পাইলেশন এবং এক্সিকিউশন।
- কম্পাইলেশন চলাকালে, Go মেমরি লেআউট প্রস্তুত করে, ফাংশন এবং এক্সপ্রেশন কম্পাইল করে।
- এক্সিকিউশন পর্যায়ে, প্রথমে
init()
এবং তারপরmain()
রান হয়। - ফাংশন এক্সপ্রেশন (যেমন,
add := func(...)
) হলোফার্স্ট ক্লাস ভ্যালু
, যা কোড সেগমেন্টে সংরক্ষিত থাকে। go build
থেকে তৈরি হওয়া বাইনারি ফাইলে কোড, ডেটা, এবং মেটাডাটা সহ প্রয়োজনীয় সবকিছু থাকে।
[Author: @ifrunruhin12, @nazma98 Date: 2025-05-01 - 2025-05-14 Category: interview-qa/class-wise ]
ক্লাস ২৬: ক্লোজার এবং Go এর অভ্যন্তরীণ মেমোরি গভীর বিশ্লেষণ 💡
এই ক্লাসে আমরা closure, escape analysis নিয়ে বিস্তারিত পড়াশুনা করব এবং অভ্যন্তরীণ মেমরি কিভাবে মেনেজ করা হয় তা জানব! 🧠🔥
📋 ক্লাস ২৬ এর কোড:
package main
import "fmt"
const a = 10
var p = 100
//Closure
func outer(money int) func() {
age := 30
fmt.Println("Age =", age)
show := func() {
money = money + a + p
fmt.Println(money)
}
return show
}
func call() {
incr1 := outer(100)
incr1() // money = 100 + 10 + 100 = 210
incr1() // money = 210 + 10 + 100 = 320
incr2 := outer(100)
incr2()
incr2()
}
func main() {
call()
}
func init() {
fmt.Println("=== Bank ===")
}
🔍 মূল বিষয়বস্তু
🔒ক্লোজার (Closure) কী?
ক্লোজার এমন একটি ফাংশন যা তার নিজস্ব স্কোপের বাইরের ভেরিয়েবলগুলোর সাথে সম্পর্ক স্থাপন করতে পারে। এই ক্ষেত্রে:
show := func() {
money = money + a + p
fmt.Println(money)
}
show
ফাংশনটি outer()
ফাংশনের ভেতরের money
ভেরিয়েবলটি মনে রাখার মাধ্যমে একটি ক্লোজার তৈরি করে।
🧠 ক্লোজার কেন গুরুত্বপূর্ণ?
ক্লোজার যুক্তি ও অবস্থাকে একসাথে ধরে রাখতে সাহায্য করে। এজন্য incr1()
এবং incr2()
একই ফাংশন ব্যবহার করলেও আলাদা money
মান ধরে রাখতে পারে।
🧮 স্ট্যাক বনাম হিপ
স্ট্যাক: দ্রুত মেমোরি, ফাংশন কল এবং লোকাল ভেরিয়েবলের জন্য ব্যবহৃত হয়।
হিপ: যখন ভেরিয়েবল ফাংশন কলের পরেও থাকা দরকার (যেমন ক্লোজারে), তখন ব্যবহৃত হয়।
money
ফাংশন outer()
শেষ হওয়ার পরও থাকতে হবে, তাই এস্কেপ অ্যানালাইসিস এটা বুঝে money
হিপে রাখে।
🧪 এস্কেপ অ্যানালাইসিস (Escape Analysis) কী?
এস্কেপ অ্যানালাইসিস হলো একটি প্রক্রিয়া যার মাধ্যমে Go কম্পাইলার ফাংশনগুলো কম্পাইল করার সময় বুঝতে পারে কোন ভেরিয়েবল স্ট্যাকে নিরাপদে রাখা যাবে আর কোনগুলো হিপে পাঠাতে হবে।
- ✅ যদি কোনো ভেরিয়েবল শুধুমাত্র ফাংশনের ভেতর ব্যবহার হয়, তাহলে সেটি স্ট্যাকে রাখা হয়।
- 🚀 যদি কোনো ভেরিয়েবল ফাংশনের বাইরে (যেমন একটি রিটার্ন করা ক্লোজারে) ব্যবহার হয়, তাহলে সেটি হিপে স্থানান্তরিত হয়।
🧱 মেমোরি সেগমেন্ট
সেগমেন্ট | কী সংরক্ষণ করে |
---|---|
কোড সেগমেন্ট | কম্পাইল করা নির্দেশাবলী এবং কনস্ট্যান্ট (ফাংশন, a ) |
ডেটা সেগমেন্ট | গ্লোবাল ভেরিয়েবল (p ) |
স্ট্যাক | লোকাল ভেরিয়েবল (age ) |
হিপ | এস্কেপিং ভেরিয়েবল (money ) |
🧠 ভিজ্যুয়ালাইজেশন
CLI-স্টাইল মেমোরি বিন্যাস
┌─────────────────────────────┐
│ কোড সেগমেন্ট │
│-----------------------------│
│ const a = 10, |
| main, call, init, outer, │
│ anonymous show function │
└─────────────────────────────┘
↓
┌─────────────────────────────┐
│ ডেটা সেগমেন্ট │
│-----------------------------│
│ var p = 100 │
└─────────────────────────────┘
↓
┌─────────────────────────────┐
│ স্ট্যাক │
│-----------------------------│
│ outer() frame │
│ age = 30 │
│ return address │
└─────────────────────────────┘
↓
┌─────────────────────────────┐
│ হিপ │
│-----------------------------│
│ money = 100 (for incr1) │
│ money = 100 (for incr2) │
└─────────────────────────────┘
প্রতিটি ক্লোজারের জন্য হিপে নিজস্ব money
থাকে। প্রতিবার outer(100)
কল করার সময় একটি নতুন মেমোরি ব্লক অ্যালোকেট করা হয়।
গারবেজ কালেক্টরের ভূমিকা 🧹
যখন কোনো ক্লোজার আর রেফারেন্স করা হয় না (যেমন incr1
বা incr2
স্কোপের বাইরে চলে যায়), তখন গারবেজ কালেক্টর
সেই হিপ মেমোরি (যেমন money
) মুছে ফেলে, যাতে অপ্রয়োজনীয় মেমোরি দখল না থাকে। অনেক ক্লোজার থাকলে কর্মদক্ষতা বজায় রাখতে এটা খুবই গুরুত্বপূর্ণ।
GC স্বয়ংক্রিয়ভাবে ট্রিগার হয় এবং প্রোগ্রামের সাথে একযোগে চলে। এটি কার্যকরভাবে কাজ করার জন্য mark-and-sweep এবং concurrent garbage collection techniques ব্যবহার করে।
🧠 সংক্ষেপে
- ক্লোজার ভেরিয়েবলের অবস্থা ধরে রাখতে পারে 🔁
- এস্কেপ অ্যানালাইসিস নির্ধারণ করে কোন ভেরিয়েবল হিপে রাখা প্রয়োজন 📦
- স্ট্যাক সাময়িক, হিপ স্থায়ী (GC 🧹 এর সাথে)
- Go মেমোরি চারটি ভাগে ভাগ করে: কোড, ডেটা, স্ট্যাক, হীপ 🧩
- GC অপ্রচলিত হীপ মেমোরি পুনর্ব্যবহারযোগ্য করে তোলে ♻️
[Author: @ifrunruhin12, @nazma98 Date: 2025-05-01 - 2025-05-17 Category: interview-qa/class-wise ]
ক্লাস ২৭: Go স্ট্রাক্ট এবং মেমোরি বিন্যাস 🧱
এই ক্লাসে আমরা স্ট্রাক্ট কীভাবে ডিফাইন ও ইন্সট্যানশিয়েট করতে হয়, এবং এগুলো কীভাবে Go এর মেমোরি মডেলের সাথে কাজ করে তা শিখব। 🧠💡
✍️ ক্লাস ২৭ এর কোড:
package main
import "fmt"
type User struct {
Name string
Age int
}
func (usr User) printDetails() {
fmt.Println("Name:", usr.Name)
fmt.Println("Age:", usr.Age)
}
func main() {
user1 := User{
Name: "Ruhin",
Age: 21,
}
user2 := User{
Name: "Mukim",
Age: 15,
}
user1.printDetails()
user2.printDetails()
}
🧠 মূল ধারণা
🧩 স্ট্রাক্ট (Struct) কী?
Go তে স্ট্রাক্ট হলো একটি ইউজার ডিফাইন্ড টাইপ(user-defined type), যা ব্যবহারকারী নিজের মতো করে তৈরি করতে পারে, যাতে সম্পর্কিত ডেটা একসাথে রাখা যায়। এটি মূলত বিভিন্ন ফিল্ডের জন্য একটি কাস্টম কন্টেইনার।
type User struct {
Name string
Age int
}
এটি User
নামে একটি নতুন টাইপ ডিফাইন করে, যার ফিল্ড হলো Name
এবং Age
।
🔨 ইনস্ট্যান্স তৈরি (Instantiation)
যখন আমরা স্ট্রাক্ট টাইপ ব্যবহার করে একটি আসল মান তৈরি করি, সেটাই ইনস্ট্যান্সিয়েশন (Instantiation).।
user1 := User{
Name: "Ruhin",
Age: 21,
}
এখানে user1
হলো User
টাইপের একটি ইনস্ট্যান্স। এটি Name
এবং Age
মানগুলো রাখার জন্য মেমোরি অ্যালোকেট করে।
🧠 মেমোরি লেআউট (ভিজ্যুয়ালাইজেশন)
┌─────────────────────────────┐
│ কোড সেগমেন্ট │
│-----------------------------│
│ main, printDetails, │
│ type User struct {...} │
└─────────────────────────────┘
↓
┌─────────────────────────────┐
│ ডেটা সেগমেন্ট │
│-----------------------------│
│ - │
│(গ্লোবাল ভেরিয়েবল থাকলে) │
└─────────────────────────────┘
↓
┌─────────────────────────────┐
│ স্ট্যাক │
│-----------------------------│
│ main() frame → │
│ user1 → Name: "Ruhin" │
│ Age: 21 │
│ user2 → Name: "Mukim" │
│ Age: 15 │
└─────────────────────────────┘
⚠️ NOTE: If a struct is returned from a function or captured by a closure, it may escape to the heap instead of stack. ⚠️ নোট: যদি কোনো স্ট্রাক্ট ফাংশন থেকে রিটার্ন হয় বা ক্লোজারে ব্যবহার হয়, তাহলে এটি স্ট্যাকের বদলে হিপে স্থানান্তরিত হতে পারে।
📋 উদাহরণ
type Book struct {
Title string
Author string
Pages int
}
book1 := Book{
Title: "1984",
Author: "George Orwell",
Pages: 328,
}
এভাবে আমরা একাধিক তথ্য নিয়ে বাস্তব জীবনের মতো মডেল তৈরি করতে পারি।
🧹 গারবেজ কালেক্টরের ভূমিকা
- যদি কোনো স্ট্রাক্ট ইনস্ট্যান্স এস্কেপ করে (ফাংশনের বাইরে ব্যবহার হয়, দীর্ঘ সময় ধরে রাখা হয়), তাহলে Go সেটি হিপে রাখে।
- Go এর গারবেজ কালেক্টর তখন সেটি ট্র্যাক করে আর ব্যবহার না হলে মেমোরি ফাঁকা করে দেয়।
- তাই ম্যানুয়ালি
free()
করার দরকার নেই, Go নিজেই হিপের মেমোরি পরিচ্ছন্ন করে।
🚀 সংক্ষেপে
type User struct {...}
হলো টাইপের তথ্য → কোড সেগমেন্ট-এ থাকে।user1 := User{...}
হলো রানটাইম ডেটা → স্ট্যাক বা হিপের রাখা হয় ব্যবহার অনুযায়ী।- স্ট্রাক্ট একসাথে অনেক ফিল্ডকে একটি লজিক্যাল ইউনিটে গুছিয়ে রাখে ✅
- মেমোরি লেআউট ব্যবহার অনুসারে বদলায় → এস্কেপ অ্যানালাইসিসের সিদ্ধান্ত অনুসারে 📦🧳
- গারবেজ কালেক্টর শুধু হিপের মেমোরি পরিষ্কার করে, স্ট্যাক নয় 🧹
প্রশ্ন: স্ট্রাক্ট কি একটি ডেটাটাইপ?
উত্তর: হ্যাঁ, ১০০% — Go-তে স্ট্রাক্ট হলো ব্যবহারকারীর তৈরি একটি ডেটাটাইপ। এটা এমন একটা "ব্লুপ্রিন্ট" যেটা দিয়ে তুমি নিজের মতো করে ডেটা অবজেক্ট বানাতে পারো। 💡
কিভাবে:
-[] Go তে int
, string
, bool
ইত্যাদির মতো প্রিমিটিভ ডেটা টাইপ থাকে।
-[] তুমি struct
ব্যবহার করে নিজের কাস্টম টাইপ তৈরি করতে পারো, যাতে একাধিক ফিল্ড একসাথে থাকে।
যেমন:
type User struct {
Name string
Age int
}
এখন User নিজেই একটা ডেটাটাইপ এর মতো কাজ করবে, আর তুমি এর ইনস্ট্যান্স তৈরি করে কাজ করতে পারো ঠিক int
বা string
এর মতো:
var u User
u.Name = "Ruhin"
u.Age = 21
এটা এমন যেন তুমি নিজের মতো একটা লেগো ব্রিক তৈরি করছো, আর যত খুশি কপি বানাতে পারো। 🧱✨
তোমার Go প্রোগ্রাম এখন স্ট্রাকচার্ড! 😎 পরের বার ডেটা মডেল করলে নিজের টাইপ তৈরি করো আর মেমোরি সেগমেন্ট বুঝে কাজ করো!
[Author: @ifrunruhin12, @nazma98 Date: 2025-05-01 - 2025-05-17 Category: interview-qa/class-wise ]
ক্লাস ২৮: Go তে রিসিভার ফাংশন (Receiver Functions)
🔑 মূল ধারণা: : রিসিভার ফাংশন
Go তে, একটি রিসিভার ফাংশন (receiver function) (যাকে method ও বলা হয়) হলো এমন একটি ফাংশন যা কোনো নির্দিষ্ট টাইপ (সাধারণত struct) এর সাথে জুড়ে থাকে। এটা আমাদের ডেটাটাইপের কোনো কাজ বা ব্যবহার যুক্ত করার সুযোগ দেয়, যেমন অন্য প্রোগ্রামিং ভাষায় অবজেক্টের method থাকে।
🧠 রিসিভার ফাংশন কি?
একটা রিসিভার ফাংশন দেখতে সাধারণ ফাংশনের মতোই, কিন্তু func
কী-ওয়ার্ড এবং ফাংশনের নামের মাঝে একটা বিশেষ receiver parameter থাকে।
func (r ReceiverType) FunctionName(params) returnType {
// function body
}
রিসিভার টাইপটি হতে পারে:
- একটি ভ্যালু রিসিভার (value receiver):
(t Type)
→ একটি কপি রিসিভ করে - একটি পয়েন্টার রিসিভার (pointer receiver):
(t *Type)
→ একটি রেফারেন্স রিসিভ করে (অরিজিনাল ডেটা পরিবর্তন করতে পারে)
🏗️ প্রোজেক্টের কোড থেকে দেখতে পাই
func (todos *Todos) add(title string) {
todo := Todo{
Title: title,
Completed: false,
CompletedAt: nil,
CreatedAt: time.Now(),
}
*todos = append(*todos, todo)
}
হলো রিসিভার এই মেথড টি এর সাথে এটাচড
todos *Todos
হলো রিসিভার- এই method টি
Todos
এর সাথে যুক্ত ([]Todo
: একটি কাস্টম টাইপ) *Todos
পয়েন্টারটি অরিজিনাল স্লাইসকে পরিবর্তন করতে দেয়
main.go
এ ব্যবহারের উদাহরণ:
todos.add("Buy milk")
🔁 রিসিভার ফাংশন কেন ব্যবহার করব?
- ডেটার সাথে সম্পর্কিত লজিক গুছিয়ে রাখা ✅
- Go-তে OOP-এর মতো আচরণ পাওয়া ✅
- কোডকে আরও পরিষ্কার ও মডুলার রাখা ✅
💡 আরও সহজ উদাহরণ
type User struct {
Name string
}
// Value receiver (no change to original)
func (u User) SayHi() {
fmt.Println("Hi, I am", u.Name)
}
// Pointer receiver (can change original)
func (u *User) ChangeName(newName string) {
u.Name = newName
}
func main() {
user := User{Name: "Ruhin"}
user.SayHi() // Hi, I am Ruhin
user.ChangeName("Mukim")
user.SayHi() // Hi, I am Mukim
}
⚙️ ⚙️ সারাংশ
টার্ম | অর্থ |
---|---|
Receiver | যে টাইপের সাথে মেথড যুক্ত থাকে (যেমন, *Todos ) |
Value Receiver | ডেটার কপি পায়; আসল ডেটা পরিবর্তন করতে পারে না |
Pointer Receiver | ডেটার রেফারেন্স পায়; আসল ডেটা পরিবর্তন করতে পারে |
📘 ভিজ্যুয়ালাইজেশন
todos.add()
কে অবজেক্টের কোনো কাজ বা আচরণ কল করার মতো ভাবা যেতে পারে:
object.method()
এই প্যাটার্নটি Todos
কে কাস্টম লজিক যোগ করার সুযোগ দেয়, যেমন add
, delete
, toggle
, print
ইত্যাদি, ঠিক Python বা Java-এর ক্লাস মেথডের মতো।
[Author: @ifrunruhin12, @nazma98 Date: 2025-05-01 - 2025-05-17 Category: interview-qa/class-wise ]
ক্লাস ২৯ - অ্যারে (Array) এবং মেমোরি লেআউট
📅 Date: April 24, 2025
🔑 মূল বিষয়বস্তু
✅ অ্যারে (Array) কী?
- অ্যারে হলো এক ধরনের ডেটা স্ট্রাকচার, যেখানে নির্দিষ্ট সাইজের একই টাইপের একাধিক উপাদান (Element) থাকে।
Go
তে, অ্যারে হলো value type, যার মানে হলো, ফাংশনে পাস করলে এর কপি তৈরি হয়।
🧠 Go তে অ্যারে
var arr [2]int // ২ টি ইন্টিজারের একটি ডিক্লেয়ার করে যার ডিফল্ট ভ্যালু: [0, 0]
arr[0] = 3 // ইনডেক্স ব্যবহার করে ভ্যালু এসাইন করে
arr[1] = 6
// সংক্ষেপে ভ্যালুসহ অ্যারে ডিক্লেয়ার করা
arr := [2]int{3, 6}
💡 ইনডেক্সিং
- Go অ্যারে জিরো-ইনডেক্সড, অর্থাৎ প্রথম উপাদান array[0] দিয়ে অ্যাক্সেস করা হয়।
⚙️ ডিফল্ট মান (Default Value)
ডিফল্ট মান মানে হলো কোনো ভেরিয়েবল বা ডেটা টাইপকে শুরুতে কোনো মান না দিলে, প্রোগ্রামিং ভাষা নিজে থেকে যে মান সেট করে।
- যদি অ্যারে ডিক্লেয়ার করা হয় কিন্তু ইনিশিয়ালাইজ না করা হয়, Go কিছু ডিফল্ট ভ্যালু সেট করে:
int
,float
ইত্যাদির জন্য0
string
এর জন্য""
(ফাঁকা স্ট্রিং)bool
এর জন্যfalse
pointers/interfaces
এর জন্যnil
🔍 মেমোরি লেআউট ভিজ্যুয়ালাইজেশন
উদাহরণ:
arr := [2]int{3, 6}
মেমোরি লেআউট
Address | Value | Meaning |
---|---|---|
0x1000 | 3 | arr[0] |
0x1004 | 6 | arr[1] |
নোট: আসল এড্রেস এখানে কল্পনা করা হয়েছে। মূল ধারণা হলো, অ্যারের সব উপাদান মেমোরিতে একসাথে (contiguously) সংরক্ষিত থাকে।
আরেকটি উদাহরণ:
arr2 := [3]string{"I", "love", "you"}
Index | Value |
---|---|
0 | "I" |
1 | "love" |
2 | "you" |
arr2[1]
এক্সেস করলে "love"
রিটার্ন করে।
🧪 ক্লাসের কোড উদাহরণসহ
package main
import "fmt"
var arr2 = [3]string{"I", "love", "you"}
func main() {
arr := [2]int{3,6}
fmt.Println(arr)
fmt.Println(arr2)
fmt.Println(arr2[1])
}
📦 সারাংশ
- অ্যারে নির্দিষ্ট সাইজের ডেটা সংরক্ষণে ভালো।
- ডিফল্ট মান সম্পর্কে সচেতন থাকুন।
- মেমোরিতে একসাথে (contiguously) সংরক্ষিত থাকে।
- Go তে অ্যারের সাথে কাজ করা সহজ, যা স্লাইসে যাওয়ার আগে ভালো ভিত্তি তৈরি করে।
[Author: @ifrunruhin12, @nazma98 Date: 2025-05-01 - 2025-05-17 Category: interview-qa/class-wise ]
ক্লাস ৩০: Go পয়েন্টার
পয়েন্টার কি?
পয়েন্টার হলো এমন একটি ভেরিয়েবল যা আরেকটি ভেরিয়েবলের মেমোরি এড্রেস সংরক্ষণ করে।
Go তে মেমোরি কয়েকটি ভাগে বিভক্ত থাকে। যেমন:
- কোড সেগমেন্ট: কম্পাইল করা প্রোগ্রামের নির্দেশনা (ফাংশন) সংরক্ষণ করে।
- ডেটা সেগমেন্ট: গ্লোবাল/স্ট্যাটিক ভেরিয়েবল এবং কনস্ট্যান্ট সংরক্ষণ করে।
- স্ট্যাক: লোকাল ভেরিয়েবল এবং ফাংশন কলের তথ্য সংরক্ষণ করে।
- হিপ: ডায়নামিকালি অ্যালোকেট করা মেমোরি সংরক্ষণ করে।
পয়েন্টারের মাধ্যমে সরাসরি মেমোরি এড্রেসের সাথে কাজ করা যায়।
গুরুত্বপূর্ণ চিহ্নগুলো:
&
(Ampersand): ভেরিয়েবলের এড্রেস পেতে ব্যবহার হয়।*
(Star/Dereference operator): মেমোরি এড্রেসে থাকা মান পেতে ব্যবহার হয়।
উদাহরণ:
x := 20
p := &x // p ভেরিয়েবল, x এর এড্রেস রাখে
*p = 30 // এড্রেস p তে থাকা মান (x) পরিবর্তন করে
fmt.Println(x) // 30
fmt.Println(p) // x এর এড্রেস
fmt.Println(*p) // 30 (এড্রেসে থাকা মান)
পয়েন্টার কেন ব্যবহার করবেন?
- ইফিসিয়েন্সি (Efficiency): বড় স্ট্রাকচার (যেমন অ্যারে) কপি না করে শুধুমাত্র তাদের মেমোরি এড্রেস পাস করা যায়।
- শেয়ারড মডিফিকেশন (Shared Modification): যখন একাধিক ফাংশনকে একই ডেটা পরিবর্তন করতে হয়।
- মেমোরি ম্যানেজমেন্ট (Memory Management): লো-লেভেল বা হাই-পারফরম্যান্স প্রোগ্রামিংয়ে বিশেষভাবে গুরুত্বপূর্ণ।
পয়েন্টার ছাড়া, প্রতিটি ফাংশন কলের সময় পুরো অবজেক্ট কপি করতে হতো। এটা ধীর গতির এবং মেমোরি অপচয় করে!
পাস বাই ভ্যালু (Pass by Value) vs পাস বাই রেফারেন্স (Pass by Reference)
পাস বাই ভ্যালু (Pass by Value):
- ভেরিয়েবলের একটি কপি পাস করা হয়।
- ফাংশনের ভেতরে পরিবর্তন অরিজিনাল ভেরিয়েবলকে প্রভাবিত করে না।
func print(numbers [3]int) {
fmt.Println(numbers)
}
arr := [3]int{1, 2, 3}
print(arr) // একটি কপি পাস
পাস বাই রেফারেন্স (Pass by Reference):
- কপি না করে ভেরিয়েবলের এড্রেস পাস করা হয়।
- ফাংশনের ভেতরে করা পরিবর্তন অরিজিনাল ভেরিয়েবলকে প্রভাবিত করে।
func print2(numbers *[3]int) {
fmt.Println(numbers)
}
arr := [3]int{1, 2, 3}
print2(&arr) // একটি পয়েন্টার পাস
স্ট্রাক্ট পয়েন্টার (and why Go is chill with them)
যখন স্ট্রাক্ট এ পয়েন্টার থাকে, Go বার বার * (dereference) করার পরিবর্তে নিজেই বুঝে নিয়ে field access দেয়।
user1 := User{
Name: "Ruhin",
Age: 21,
Salary: 0,
}
p2 := &user1
fmt.Println(p2.Age) // no need to write (*p2).Age
Go নিজে থেকে pointer কে dereference করে field টা দেয়। অসাধারণ, তাই না?
Full Code Example from Class:
package main
import "fmt"
type User struct {
Name string
Age int
Salary float64
}
func print(numbers [3]int) {
fmt.Println(numbers)
}
func print2(numbers *[3]int) {
fmt.Println(numbers)
}
func main() {
x := 20
p := &x
*p = 30
fmt.Println(x) // 30
fmt.Println("Address:", p)
fmt.Println("Value:", *p)
arr := [3]int{1, 2, 3}
print(arr) // pass by value
print2(&arr) // pass by reference
user1 := User{
Name: "Ruhin",
Age: 21,
Salary: 0,
}
p2 := &user1
fmt.Println(p2.Age)
}
মেমরি লেআউটের ভিজ্যুয়ালাইজেশন (CLI)
+--------------------+----------------------------------+
| সেগমেন্ট | কি আছে |
+--------------------+----------------------------------+
| Code Segment | main(), print(), print2() |
| Data Segment | (এখানে কোনো গ্লোবাল ভ্যারিয়েবল নেই) |
| Stack | arr [3]int {1,2,3}, x=30 |
| | p (pointer to x) |
| | user1 (User struct) |
| | p2 (pointer to user1) |
| Heap | (এই প্রোগ্রামে ব্যবহার হয়নি) |
+--------------------+----------------------------------+
বিস্তারিত মেমরি ভিজ্যুয়ালাইজেশন (এড্রেস এবং মানসহ)
Stack Memory:
[ Address 0x1000 ] x = 30
[ Address 0x1004 ] p -> 0x1000 (address of x)
[ Address 0x1008 ] arr = [1, 2, 3]
[ Address 0x1010 ] user1 = {"Ruhin", 21, 0.0}
[ Address 0x1018 ] p2 -> 0x1010 (address of user1)
Code Segment:
- Compiled code of main, print, print2
Data Segment:
- খালি (কোন গ্লোবাল ভ্যারিয়েবল নেই)
Heap:
- এই প্রোগ্রামে ব্যবহার হয়নি
আরও উদাহরণ: পয়েন্টার ব্যবহার করে দুইটি নম্বর বিনিময় (Swap) করা
পয়েন্টার ছাড়া (FAIL):
func swap(x, y int) {
temp := x
x = y
y = temp
}
func main() {
a, b := 1, 2
swap(a, b)
fmt.Println(a, b) // still 1 2
}
পয়েন্টার ব্যবহার করে (WIN):
func swap(x, y *int) {
temp := *x
*x = *y
*y = temp
}
func main() {
a, b := 1, 2
swap(&a, &b)
fmt.Println(a, b) // 2 1
}
সংক্ষিপ্ত সারাংশ
&
দিয়ে ভেরিয়েবলের ঠিকানা পাওয়া যায়।*
দিয়ে ঠিকানায় থাকা মান পাওয়া যায়।- Pointers = efficient + powerful
- struct pointer থাকলে Go নিজে থেকে field access দেয়, আলাদা dereference করার দরকার নেই।
- বড় ডেটা (array, struct) পাস করার সময় পয়েন্টার ব্যবহার করে মেমোরি সেভ করা যায়।
Bro Tip:
When in doubt, think: "Am I copying a whole dang castle, or just giving a map to it?"
Pointers = the map. ✅
[Author: @ifrunruhin12, @nazma98 Date: 2025-05-01 - 2025-05-17 Category: interview-qa/class-wise ]
📚 Class 31 : Go Slice
🚀 Main Topics
- Slice কী?
- একটি Slice এ কয়টি অংশ থাকে?
- Slice এর Pointer, Length, এবং Capacity নির্ণয় করা
- বিদ্যমান Array থেকে Slice তৈরি
- বিদ্যমান Slice থেকে নতুন Slice তৈরি
- Slice Literal (সরাসরি ঘোষণা)
make()
দিয়ে Slice তৈরি (শুধু length)make()
দিয়ে Slice তৈরি (length এবং capacity)- খালি বা Nil Slice তৈরি
- Slice এ নতুন element যোগ করা (append)
append
করার সময় অভ্যন্তরীণ প্রক্রিয়া (Heap এবং Underlying Array)- Underlying Array কীভাবে dynamic ভাবে বাড়ে
- কিছু মজার উদাহরণ এবং ইন্টারভিউ প্রশ্ন
- Variadic Functions
🧠 ১. Slice কী?
- Slice হলো Go এর একটি flexible data structure।
- এটি মূলত array এর উপরে নির্মিত একটি dynamic view।
- array এর মত হলেও, slice এর সাইজ পরিবর্তন করা যায় (বড় বা ছোট করা যায়)।
মূল পয়েন্ট:
- Slice, array নয়।
- Slice, array এর উপরে তৈরি হয়।
🔥 ২. একটি Slice এর কয়টি অংশ থাকে?
Slice মূলত একটি struct যা তিনটি অংশ নিয়ে গঠিত:
struct Slice {
pointer *T // points underlying array
length int // current elements number
capacity int // maximum elements (until reallocation)
}
Slice কে মূলত একটি array এর "window" হিসেবে ভাবা যেতে পারে।
🕵️♂️ ৩. Pointer, lenth এবং capacity নির্ধারণ করার উপায়
নিম্নোক্ত built-in ফাংশন ব্যবহার করে Slice এর length এবং capacity বের করা যায়:
len(slice)
➡️ Lengthcap(slice)
➡️ Capacity
উদাহরণ:
s := arr[1:4] // index 1 to 3
fmt.Println(len(s)) // 3
fmt.Println(cap(s)) // index 1 to end of the array
🏗 ৪. Array থেকে Slice তৈরি করা
arr := [6]string{"This", "is", "a", "Go", "interview", "Questions"}
s := arr[1:4] // slice ["is", "a", "Go"]
pointer
:arr
এর index 1 নির্দেশ করেlength
: 3 (index 1 to 3)capacity
: 5 (index 1 to 5)
🔄 ৫. Slice থেকে নতুন Slice তৈরি
s1 := s[1:2] // Slice "a"
s1
Slice টি একই Array এর একটি view!s1
পরিবর্তন করলেarr
এর মানও পরিবর্তিত হতে পারে।
✍️ 6. Slice Literal
একটি Slice তৈরি করতে সরাসরি মান ব্যবহার করা যায়, আলাদা করে Array তৈরি করার প্রয়োজন নেই।
s2 := []int{3, 4, 7}
এখানে Go automatically একটি underlying Array তৈরি করে।
🏗️ ৭. make() দিয়ে একটি Slice তৈরি করা
s3 := make([]int, 3)
make()
দিয়ে ৩টি শূন্য মান (zero) সহ একটি Slice তৈরি করে। অর্থাৎ, ৩টি empty element থাকবে।len = 3
,cap = 3
🏗️🏗️ ৮. make()
দিয়ে একটি Slice তৈরি করা (length এবং capacity)
s4 := make([]int, 3, 5)
len = 3
, কিন্তু capacitycap = 5
পর্যন্ত হতে পারে reallocation এর আগ পর্যন্ত
🕳 9. Empty / Nil Slice Slice তৈরি
var s5 []int
len = 0
,cap = 0
- Still valid! এতে নতুন element যোগ (append) করা যাবে।
➕ ১০. Slice এ নতুন element append করা
s6 := append(s6, 1)
- Go নিজে থেকে underlying Array বড় করে।
- অনেক বড় Array তৈরি এবং আগের element গুলো copy করার কাজও করে থাকে।
🧬 ১১. append করার সময় আসলে কী হয়?
যখন একটি Slice এর capacity পূর্ণ হয়:
- একটি নতুন Array (সাধারণত দ্বিগুণ সাইজের) তৈরি করা হয়।
- আগের Array এর সমস্ত elements নতুন Array তে কপি করা হয়।
এ কারণেই কখনও কখনও append করা দ্রুত মনে হয় এবং কখনও বড় মেমরি অপারেশন তৈরি করতে পারে।
📈 ১২. Underlying Array কিভাবে বৃদ্ধি পায়:
যে প্যাটার্নে capacity পায় (Capacity Growth Pattern): (simplified)
- Cap 1 ➡️ 2 ➡️ 4 ➡️ 8 ➡️ 16 ➡️ ...
এটি একটি optimization technique যা নিশ্চিত করে যেন append অপারেশনগুলো গড়ে O(1)
সময়ে সম্পন্ন হয়।
Go Slice বৃদ্ধি: len
এবং cap
এর dynamics বোঝা
Go Slice একটি শক্তিশালী এবং flexible data structure, যা dynamic Array এর মতো কাজ করে। এর একটি মূল বৈশিষ্ট্য হলো, যখন নতুন element যোগ করা হয়, তখন Slice নিজে নিজেই বৃদ্ধি পায়। Slice কীভাবে এবং কখন বৃদ্ধি পায়, আর এর মেমরি অ্যালোকেশনের পদ্ধতি বুঝলে অনেক efficient program design করা সম্ভব।
এখন আমরা Go Slice এর বৃদ্ধির পদ্ধতি বিশ্লেষণ করব:
- যদি Slice এর
len
এবংcap
1024
-এর কম হয়, তাহলে এটি সাধারণত দ্বিগুণ (2x) বৃদ্ধি পায়। len
এবংcap
,1024
ছাড়িয়ে গেলে, এটি প্রায় 25% হারে বৃদ্ধি পায়।- Slice কেন নির্দিষ্ট পরিমাণে (যেমন 1024 থেকে 1280) না বাড়িয়ে বড় ব্লকে (যেমন 1536) বাড়ে, সেটিও ব্যাখ্যা করা হবে।
Slice Growth Overview
Go তে slice মূলত array এর উপরে ভিত্তি করে কাজ করে। যখন একটি slice এ নতুন element append করা হয়, তখন প্রয়োজনে Go একটি বড় array তৈরি করে এবং পুরানো element গুলো তাতে কপি করে। এই প্রসেসটি নির্ভর করে Go কিভাবে নতুন capacity নির্ধারণ করে এবং মেমরি allocate করে।
১২.১. ছোট Slice এর ক্ষেত্রে দ্বিগুণ বৃদ্ধি (len(cap) < 1024
)
যখন slice ছোট থাকে (অর্থাৎ, এর len
এবং cap
দুটোই 1024 এর কম), তখন Go সাধারণত capacity দ্বিগুণ করে। এর মানে, যখন slice এ একটি element যোগ করা হয় এবং নতুন মেমরি প্রয়োজন হয়, তখন Go আগের capacity এর দ্বিগুণ আকারের একটি নতুন array তৈরি করে এবং পুরানো element গুলো সেখানে কপি করে। Slice এর len
১ বাড়বে, কিন্তু cap
দ্বিগুণ হবে।
উদাহরণ:
s := []int{1, 2, 3}
fmt.Println(len(s), cap(s)) // len: 3, cap: 3
s = append(s, 4)
fmt.Println(len(s), cap(s)) // len: 4, cap: 6
s = append(s, 5)
fmt.Println(len(s), cap(s)) // len: 5, cap: 6
- প্রথমে, slice এর
len
৩ এবংcap
৩ থাকে। - চতুর্থ element যোগ করার সময়, slice এর capacity ৩ থেকে দ্বিগুণ হয়ে ৬ হয়ে যায়।
- পরবর্তী অ্যাপেন্ডে, slice এর capacity ৬ ই থাকবে কারণ
len
<cap
।
১২.২. বড় Slice এর ক্ষেত্রে ২৫% বৃদ্ধি (len(cap) >= 1024
)
যখন slice এর len
এবং cap
1024 বা তার বেশি হয়, তখন Go দ্বিগুণের পরিবর্তে বর্তমান capacity এর ২৫% বৃদ্ধি করে। এই কৌশলটি ঘন ঘন মেমরি reallocation এড়াতে এবং অপ্রয়োজনীয় মেমরি অপচয় কমাতে সহায়তা করে।
উদাহরণ:
s := make([]int, 1024) // len: 1024, cap: 1024
fmt.Println(len(s), cap(s))
s = append(s, 1025) // len: 1025, cap: 1280 (1024 + 25% of 1024)
fmt.Println(len(s), cap(s))
s = append(s, 1300) // len: 1300, cap: 1600 (1280 + 25% of 1280)
fmt.Println(len(s), cap(s))
- শুরুতে, আমরা length এবং capacity 1024 সহ একটি slice তৈরি করি।
- পরের element append করলে slice এর capacity 1024 থেকে 1280 হয়, যা 1024 এর সাথে ২৫% যোগ করে পাওয়া যায়।
- আরেকটি element append করলে capacity 1600 হয় (1280 এর সাথে ২৫% যোগ করে)।
১২.৩. মেমরি ব্লকের ভূমিকা (যেমন, 1536 ক্ষমতার Slice)
যখন slice এর len
এবং cap
1024 এর কাছাকাছি বা তার বেশি হয়, তখন Go সর্বদা নিখুঁত গণনা অনুযায়ী মেমরি বরাদ্দ করে না। এর পরিবর্তে এটি সিস্টেম মেমরি বরাদ্দের ধরণ অনুযায়ী Optimal Memory Block ব্যবহার করে।
উদাহরণস্বরূপ, যদি একটি slice এর capacity 1024 এর কাছাকাছি থাকে, পরবর্তী বরাদ্দ সরাসরি 256 যোগ করে 1280 না হয়ে, এর থেকে বড় 1536 এর মতো ব্লকে হতে পারে। এটি বড় মেমরি ব্লকের জন্য আরও কার্যকর মেমরি ব্যবহারে সহায়তা করে।
কেন 1536 এর পরিবর্তে 1280?
এটি মূলত Hardware Memory Alignment এর উপর নির্ভর করে। 1536 সংখ্যাটি বেছে নেওয়া হয় কারণ এটি সাধারণত 2-এর গুণিতক আকারের মেমরি ব্লকের সাথে ভালোভাবে মিলে যায় এবং আধুনিক CPU এবং মেমরি সিস্টেমের জন্য optimize করা। মেমরি অ্যালোকেশন সাধারণত সিস্টেমের memory page size বা cache line এর সাথে সামঞ্জস্য রেখে বড় ব্লকে করা হয়, যা মেমরি অ্যাক্সেসকে আরও ইফিশিয়েন্ট করে তোলে।
উদাহরণ (memory alignment):
s := make([]int, 1024) // len: 1024, cap: 1024
fmt.Println(len(s), cap(s)) // 1024, 1024
s = append(s, 1025) // len: 1025, cap: 1536 (next optimal block size)
fmt.Println(len(s), cap(s)) // 1025, 1536
- 1024 থেকে 1536 এ capacity বৃদ্ধি হয়, কারণ 1536 একটি বেটার মেমরি ব্লক যা সিস্টেমের ইফিশিয়েন্ট মেমরি অ্যালোকেশন করে।
১২.৪. কেন এমন হয়?
efficiency considerations Go সরাসরি 256 করে বৃদ্ধি করে না (যেমন আমরা মনে করি 1024 থেকে 1280)। কারণ এটি ইফিশিয়েন্সি বৃদ্ধির জন্য গুরুত্বপূর্ণ। এই অ্যালোকেশন স্ট্র্যাটেজির ফলে ঘন ঘন রি-অ্যালোকেশন এড়ানো যায় এবং অপ্রয়োজনীয় মেমরি অপচয় কমে যায়। বরং বড় ব্লকে (1536) মেমরি বরাদ্দ করে Go রানটাইম নিশ্চিত করে Sliceে পর্যাপ্ত capacity আছে আরও element এপেন্ড করার জন্য এবং খুব তাড়াতাড়ি Sliceকে বাড়াতে হবে না।
এর ফলে আরও ভালো performance পাওয়া যায়, বিশেষ করে যখন slice দ্রুত বৃদ্ধি পায়।
Conclusion
Go-এর slice বৃদ্ধি কৌশল অনেক ইফিশিয়েন্ট কোড লিখা সম্ভব। ছোট সাইজের slice এর ক্ষেত্রে, Go capacity দ্বিগুণ করে যাতে কম রি-অ্যালোকেশনে আরও element ধারণ করতে পারে। বড় slice (1024 এবং এর বেশি) হলে, এটি capacity ২৫% বৃদ্ধি করে এবং মাঝে মাঝে অপ্টিমাল মেমরি ব্লকের সাথে সামঞ্জস্য রাখে। এই পদ্ধতিটি slice কে দ্রুত এবং মেমরি সাশ্রয়ী করে তোলে।
🤯১৩. কিছু ইন্টারেস্টিং ইন্টারভিউ প্রশ্নের উদাহরণ
⚡ Same Underlying Array Trick
var x []int
x = append(x, 1)
x = append(x, 2)
x = append(x, 3)
y := x
x = append(x, 4)
y = append(y, 5)
x[0] = 10
fmt.Println(x)
fmt.Println(y)
-x এবং y একই backing array শেয়ার করে
- একটিতে পরিবর্তন (mutation) করলে দুটোরই মান পরিবর্তিত হতে পারে।
কিন্তু cap
অতিক্রম করে অ্যাপেন্ড করলে, তারা আলাদা Array তে বিভক্ত হতে পারে।
🛠 ১৪. Variadic Functions
কোন ফাংশন ...
(ellipsis) operator ব্যবহার করে অসংখ্য argument receive করতে পারে।
func variadic(numbers ...int) {
fmt.Println(numbers)
}
variadic(2, 3, 4, 6, 8, 10)
এখানে numbers
কিন্তু একটি slice!
🧠 RAM এ Slice এর visualization (arr এবং s এর জন্য)
Array arr (indexes):
[0] "This"
[1] "is" <- s.ptr points here
[2] "a"
[3] "Go"
[4] "interview"
[5] "Questions"
Slice s:
- ptr = &arr[1]
- len = 3 ("is", "a", "Go")
- cap = 5 (from "is" to "Questions")
Memory Visualization:
+----+--+-+--+---------+---------+
|This|is|a|Go|interview|Questions|
+----+--+-+--+---------+---------+
^ ^ ^
s[0] s[1] s[2]
📄 Full Code with Detailed Comments
package main
import "fmt"
func main() {
// Create an array of strings
arr := [6]string{"This", "is", "a", "Go", "interview", "Questions"}
fmt.Println(arr)
// Create a slice from array indexes 1 to 3 (exclusive of 4)
s := arr[1:4]
fmt.Println(s) // [is a Go]
// Create a slice from a slice
s1 := s[1:2]
fmt.Println(s1) // [a]
fmt.Println(len(s1)) // 1
fmt.Println(cap(s1)) // 4 (capacity depends on the underlying array)
// Slice literal
s2 := []int{3, 4, 7}
fmt.Println("slice", s2, "lenght:", len(s2), "capacity:", cap(s2))
// make() function with length only
s3 := make([]int, 3)
s3[0] = 5
fmt.Println(s3)
fmt.Println(len(s3))
fmt.Println(cap(s3))
// make() function with length and capacity
s4 := make([]int, 3, 5)
s4[0] = 5
fmt.Println(s4)
fmt.Println(len(s4))
fmt.Println(cap(s4))
// Empty slice
var s5 []int
fmt.Println(s5) // []
// Appending elements to empty slice
var s6 []int
s6 = append(s6, 1)
fmt.Println(s6) // [1]
var s7 []int
s7 = append(s7, 1, 2, 3)
fmt.Println(s7, len(s7), cap(s7)) // [1 2 3] 3 3
// Interview question: Sharing underlying array
var x []int
x = append(x, 1)
x = append(x, 2)
x = append(x, 3)
y := x
x = append(x, 4)
y = append(y, 5)
x[0] = 10
fmt.Println(x) // [10 2 3 5]
fmt.Println(y) // [10 2 3 5]
// Another interview question
slc := []int{1, 2, 3, 4, 5}
slc = append(slc, 6)
slc = append(slc, 7)
slcA := slc[4:]
slcY := changeSlice(slcA)
fmt.Println(slc) // [1 2 3 4 10 6 7]
fmt.Println(slcY) // [10 6 7 11]
fmt.Println(slc[0:8]) // [1 2 3 4 10 6 7 11]
// Variadic function call
variadic(2, 3, 4, 6, 8, 10)
}
// Function that changes the slice passed
func changeSlice(a []int) []int {
a[0] = 10
a = append(a, 11)
return a
}
// Variadic function that takes multiple integers
func variadic(numbers ...int) {
fmt.Println(numbers)
fmt.Println(len(numbers))
fmt.Println(cap(numbers))
}
[Author: @ifrunruhin12, @nazma98 Date: 2025-05-01 - 2025-05-18 Category: interview-qa/class-wise ]
Class 36:কম্পিউটার আর্কিটেকচার এবং ইতিহাস
🕰️ কম্পিউটার ইতিহাসের সংক্ষিপ্ত বিবরণ
মানুষ তার কাজকে সহজ করতে যন্ত্র উদ্ভাবন করেছে, আর এরই ধারাবাহিকতায় এসেছে কম্পিউটার।
-
২৭০০ খ্রিস্টপূর্বে, প্রথম গণনা যন্ত্র Abacus আবিষ্কৃত হয়। এটি কাঠ বা বাঁশের তৈরি একটি ফ্রেমে রাখা গুটির মাধ্যমে কাজ করত।
-
১৭০৩ সালে, Gottfried Wilhelm Leibniz সর্বপ্রথম Binary Number System আবিষ্কার করেন, যা কম্পিউটারের ভিত্তি গড়ে দেয়।
-
১৮৩৭ সালে, Charles Babbage আবিষ্কার করেন পৃথিবীর প্রথম মেকানিক্যাল কম্পিউটার, যার নাম Analytical Engine।
এজন্য তাকে Father of the Computer বলা হয়।
🧾 Analytical Engine এবং Punch Card
- Analytical Engine-এ ইনপুট দেয়ার জন্য Punch Card ব্যবহার করা হতো।
- এটি একধরনের শক্ত কাগজ যেটাতে গর্ত করে তথ্য encode করা হতো।
- গর্তের উপস্থিতি এবং অনুপস্থিতির ভিত্তিতে কম্পিউটার বুঝত কোন নির্দেশনা দেয়া হচ্ছে।
👩💻 বিশ্বের প্রথম প্রোগ্রামার
Ada Lovelace (১৮১৫–১৮৫২) ছিলেন বিশ্বের প্রথম প্রোগ্রামার।
তিনি ১৮৪৩ সালে Charles Babbage-এর Analytical Engine-এর জন্য একটি অ্যালগরিদম লিখেন, যেটি Bernoulli Numbers গণনা করতে পারত।
🧠 Theoretical Computer Science এর জনক
Alan Turing কে বলা হয় Father of Theoretical Computer Science।
Alan Turing-কে Father of Theoretical Computer Science বলা হয় কারণ তিনি কম্পিউটারের theoretical foundation গড়ে তোলেন এবং Turing Machine ধারণা দেন। যেগুলোর ভিত্তিতেই আধুনিক কম্পিউটার বিজ্ঞান দাঁড়িয়ে আছে।
১. Turing Machine (1936)
Turing Machine ছিল একটি কল্পিত যন্ত্র, যা নির্দিষ্ট নিয়মে ইনপুট পেলে যে কোনো গণনাযোগ্য সমস্যার সমাধান করতে পারত। এটি প্রথম বুঝিয়ে দেয়:
- কোন সমস্যাগুলো কম্পিউটারে সমাধানযোগ্য (computable)
- আর কোন সমস্যাগুলো সমাধানযোগ্য নয় (non-computable)
এই ধারণা থেকেই আধুনিক কম্পিউটার ও অ্যালগরিদম ডিজাইনের ভিত্তি তৈরি হয়েছে।
📌 উদাহরণ: আজকের সফটওয়্যার, কোড, প্রোগ্রাম - সবই Turing Machine-এর theoretical foundation এর উপর তৈরি।
২. Computability Theory জন্ম
Turing-এর গবেষণা থেকেই তৈরি হয় Computability Theory। এই শাখা ঠিক করে দেয়:
- কোন কাজগুলো কম্পিউটারে করা সম্ভব,
- কোন কাজগুলো অসম্ভব।
এই শাখাই ছিল Theoretical Computer Science এর মূল ভিত্তি।
৩. কোড ব্রেকিং ও কৃত্রিম বুদ্ধিমত্তার সূচনা
-
দ্বিতীয় বিশ্বযুদ্ধে Turing জার্মানির Enigma Code ভাঙার জন্য একটি মেশিন (Bombe) তৈরি করেন। এটি আধুনিক কম্পিউটারের ধারণা বাস্তবে রূপ দিতে সহায়তা করে।
-
তিনি একটি বিখ্যাত প্রশ্ন করেন:
"Can machines think?"
এই প্রশ্ন থেকেই Artificial Intelligence (AI) এর ধারণার সূচনা হয়।
Alan Turing শুধু একজন গাণিতিক বিজ্ঞানী ছিলেন না, তিনি ছিলেন ভবিষ্যতের প্রযুক্তির দিকদর্শক। তার চিন্তাধারা এবং তাত্ত্বিক মডেলগুলো আজকের পুরো কম্পিউটার বিজ্ঞানের ভিত্তি।
এই কারণেই তাঁকে বলা হয়: "Father of Theoretical Computer Science"
💡 প্রথম ইলেকট্রনিক কম্পিউটার
- ১৯৪৫ সালে, ENIAC (Electronic Numerical Integrator and Computer) তৈরি করা হয়।
- এটি ছিল বিশ্বের প্রথম ইলেকট্রনিক জেনারেল-পারপাস কম্পিউটার।
- এতে Vacuum Tube ব্যবহৃত হতো, যা অনেক বড় ও গরম হতো।
কিভাবে বিশাল আকৃতির কম্পিউটার ছোট হলো?
প্রথম দিকের কম্পিউটারগুলো যেমন ENIAC, সেগুলো তৈরি হতো Vacuum Tube দিয়ে। এগুলোর আকার ছিল বিশাল, অনেক বিদ্যুৎ খরচ হতো এবং খুব গরম হয়ে যেত। অনেক সময় একটি ছোট সমস্যার জন্য পুরো মেশিন বন্ধ হয়ে যেত। তাই, বিজ্ঞানীরা খুঁজছিলেন এমন কোনো প্রযুক্তি যা:
- আকারে ছোট হবে,
- কম বিদ্যুৎ খরচ করবে,
- কম তাপ উৎপন্ন করবে,
- এবং নির্ভরযোগ্যভাবে কাজ করবে।
এই প্রয়োজন থেকেই শুরু হয় কম্পিউটারের বিবর্তনের যাত্রা।
পরিবর্তনের ধাপসমূহ:
১. Transistor (1947):
Vacuum Tube-এর বিকল্প হিসেবে Transistor আবিষ্কৃত হয়। এটি ছিল একধরনের ছোট ইলেকট্রনিক যন্ত্রাংশ, যেটি একই কাজ করতে পারতো অনেক কম জায়গা ও শক্তি দিয়ে। ট্রানজিস্টরের সুবিধা হলো:
- এটি ছোট আকারের,
- কম গরম হয়,
- বেশি দিন টেকে।
এই কারণে Transistor ব্যবহার করে কম্পিউটার আরও ছোট ও কার্যকর হলো।
২. Integrated Circuit (IC) (1958):
এরপর বিজ্ঞানীরা একাধিক ট্রানজিস্টরকে একসাথে একটি ছোট চিপে বসিয়ে তৈরি করলেন Integrated Circuit (IC)। এর ফলে:
- একই সার্কিটে অনেক কাজ করা সম্ভব হলো,
- কম খরচে অনেক শক্তিশালী যন্ত্র তৈরি করা গেল,
- কম্পিউটার আরও ছোট ও দ্রুততর হলো।
৩. Microprocessor (1971):
এরপর আসে সবচেয়ে বড় বিপ্লব – Microprocessor। Intel 4004 ছিল পৃথিবীর প্রথম মাইক্রোপ্রসেসর। এটি একটি ছোট চিপ, যেখানে পুরো একটি CPU-এর কাজ করা যায়। এর ফলে:
- কম্পিউটার তৈরি করা আরও সহজ হলো,
- ব্যক্তি পর্যায়ে কম্পিউটার (Personal Computer) আসা শুরু করল,
- ঘরে বসে মানুষ কম্পিউটার ব্যবহার করতে পারল।
৪. VLSI (Very Large Scale Integration):
সবশেষে, VLSI প্রযুক্তির মাধ্যমে হাজার হাজার ট্রানজিস্টর ও সার্কিট একসাথে একটি ছোট চিপে স্থাপন করা সম্ভব হয়। এর ফলাফল:
- কম্পিউটার আরও বেশি শক্তিশালী হলো,
- মোবাইল, ল্যাপটপ, স্মার্ট ডিভাইসের মতো ছোট যন্ত্রে কম্পিউটার শক্তি যোগ হলো।
🧮 বিট ও বাইট
কম্পিউটার তথ্য সংরক্ষণ ও প্রক্রিয়াকরণে বিট (bit) এবং বাইট (byte) ব্যবহার করে।
- ১ Byte = ৮ Bits
- ১ Bit = ০ অথবা ১ (Binary value)
🧠 র্যাম (RAM) ও মেমোরি
RAM এর পূর্ণরূপ হলো Random Access Memory।
এটি একটি Primary Memory, যা ভলাটাইল (Volatile) মেমোরি।
এর মানে হলো, কম্পিউটার বন্ধ হলে RAM-এ সংরক্ষিত তথ্য মুছে যায়।
RAM সাধারণত কাজের সময়কার তথ্য বা চলমান প্রোগ্রামগুলো সাময়িকভাবে রাখে।
অন্যদিকে,
- SSD (Solid State Drive) এবং
- HDD (Hard Disk Drive)
এই দুটি হলো Secondary Memory, যেখানে দীর্ঘমেয়াদে ডেটা সংরক্ষণ করা যায় এবং কম্পিউটার বন্ধ হলেও তথ্য থাকে।
🖥️ CPU (Central Processing Unit)
CPU-এর ভেতরে নিচের অংশগুলো থাকে:
- ALU (Arithmetic Logic Unit): গাণিতিক ও লজিক্যাল কাজ করে
- CU (Control Unit): CPU-এর সব কার্যক্রম নিয়ন্ত্রণ করে
- Registers: অস্থায়ীভাবে তথ্য ধরে রাখে
- Cache Memory: দ্রুত গতির ছোট মেমোরি, বারবার ব্যবহৃত ডেটা রাখে
💼 IBM, Apple, এবং Microsoft-এর প্রাথমিক কম্পিউটার ইতিহাস
🖥️ IBM (International Business Machines)
- 1952 সালে, IBM তৈরি করে তাদের প্রথম commercial computer - IBM 701।
- এরপর 1964 সালে, IBM তৈরি করে System/360, একটি Mainframe Computer সিরিজ যা ব্যবসা, গবেষণা এবং সরকারে বিপ্লব আনে।
- এই কম্পিউটারগুলোর মেমোরি ছিল kilobytes (KB) লেভেলের - সাধারণত 8KB থেকে 512KB পর্যন্ত।
- প্রাথমিকভাবে 8-bit বা 16-bit architecture ব্যবহৃত হতো, পরবর্তীতে তা 32-bit হয়।
📌 বিষেষত্ব:
IBM-এর Mainframe কম্পিউটারগুলো ছিল অনেক বড় এবং ভারী, কিন্তু শক্তিশালী। আজও ব্যাংকিং বা সরকারি কাজে Mainframe-এর ভিত্তি ব্যবহার করা হয়।
🍎 Apple Inc.
- 1976 সালে, Steve Jobs এবং Steve Wozniak তৈরি করেন Apple I - একটি single-board পার্সোনাল কম্পিউটার।
- 1977 সালে, Apple II বাজারে আসে, যা প্রথম color graphics, keyboard, and floppy drive সাপোর্ট করত।
- Apple I তে ছিল 8-bit MOS 6502 processor এবং 4KB RAM।
- Apple II তেও ছিল 8-bit processor, এবং RAM ছিল 4KB থেকে 48KB পর্যন্ত উন্নত করা যেত।
📌 Apple-এর ভূমিকা:
Apple ই ছিল সেই কোম্পানি যারা পার্সোনাল কম্পিউটারকে সাধারণ মানুষের নাগালে এনে দেয়। Apple II ব্যাপকভাবে জনপ্রিয় হয় স্কুল, ব্যবসা এবং ঘরের ব্যবহারের জন্য।
🪟 Microsoft
- 1980 সালে, Microsoft তৈরি করে MS-DOS (Microsoft Disk Operating System), যেটা IBM PC-তে ব্যবহার হতো।
- পরে 1985 সালে, তারা তৈরি করে Windows 1.0 - একটি GUI-ভিত্তিক অপারেটিং সিস্টেম যা MS-DOS-এর উপর কাজ করত।
- এই অপারেটিং সিস্টেমগুলো প্রথমে 8-bit এবং 16-bit architecture এ চলে, পরে 32-bit এবং 64-bit OS আসে।
- Windows OS এর কারণে কম্পিউটার ব্যবহার অনেক সহজ হয়, এবং সাধারণ মানুষও কম্পিউটার চালাতে আগ্রহী হয়।
📌 Microsoft-এর অবদান:
MS-DOS এবং Windows-এর মাধ্যমে Microsoft সফটওয়্যার ইন্ডাস্ট্রিতে বিপ্লব আনে। তারা হার্ডওয়্যার না বানিয়ে সফটওয়্যারের উপর ফোকাস করে, যার ফলে তাদের OS অনেক ধরনের কম্পিউটারেই চলত।
🔢 Bit Architecture Summary:
Year | Company | Product | Bit | RAM (approx.) |
---|---|---|---|---|
1952 | IBM | IBM 701 | 36-bit | 8KB+ |
1964 | IBM | System/360 | 8/16-bit | 16–512KB |
1976 | Apple | Apple I | 8-bit | 4KB |
1977 | Apple | Apple II | 8-bit | 4–48KB |
1980 | Microsoft | MS-DOS (for IBM PC) | 16-bit | 64–640KB |
1985 | Microsoft | Windows 1.0 | 16-bit | ~1MB |
IBM শুরুতে মেইনফ্রেম বানালেও পরে পার্সোনাল কম্পিউটারে রূপান্তর হয়।
Apple এবং Microsoft ছিল সেই দুই কোম্পানি যারা সাধারণ মানুষের হাতে কম্পিউটার এনে দেয় - Apple হার্ডওয়্যার দিয়ে আর Microsoft সফটওয়্যার দিয়ে।
তাদের তৈরি কম্পিউটার ও OS গুলোর bit size শুরুতে 8-bit, পরে 16-bit → 32-bit → 64-bit পর্যন্ত উন্নত হয়, যার ফলে গতি, ক্ষমতা ও ব্যবহারযোগ্যতা অনেক বাড়ে।
[Author:@shahriar-em0n Date: 2025-06-05 Category: interview-qa/class-wise ]
✨ CLass 33 - Into The Operating System
🖥️ ENIAC ও Punch Card
ENIAC (Electronic Numerical Integrator and Computer) ছিল একেবারে প্রথম দিকের একটি general purpose computer যা Punch card ব্যবহার করত:
- Input (Data এবং Instruction)
- Output (Result)
- Storage (Storing temporary data)
ENIAC সাধারণত IBM এর ৮০ কলামের Punch card ব্যবহার করত।
🧠 Punch Card (80x12)
- শক্ত কাগজ, যাতে ৮০টি কলাম ও ১২টি সারি থাকে।
- ছিদ্র দিয়ে তথ্য encode করা হয়
- ছিদ্র =
1
- ছিদ্র না থাকলে =
0
🧾 Punch card RAM এ লোড এবং Program execute
- Punch Card তৈরি
- প্রোগ্রামের কোড বা ডেটা আগে কাগজে Punch card এ লেখা হতো (প্রতিটি কার্ড = ১ লাইন কোড বা তথ্য)।
- keypunch machine দিয়ে ছিদ্র করা হতো।
- Computer এ Feed
- Punch card গুলো card reader এ ঢোকানো হতো।
- Reader ছিদ্রগুলো পড়ে Binary signal এ (1 বা 0) রূপান্তর করত।
- RAM এ Load
- Binary signal গুলো কম্পিউটারের Memory ইউনিটে পাঠানো হতো।
- সেই সময়কার RAM ছিল টিউব বা flip-flop ধরনের মেমোরি।
- প্রতিটি instruction বা data নির্দিষ্ট location এ সংরক্ষিত হতো।
- Execution
- কম্পিউটারের control unit(CU), memory থেকে একে একে instruction নিত।
- Pointing Register (Program Counter) প্রথমে প্রথম instruction address কে point করে।
- CPU সেই instruction -> fetch -> decode -> execute করে।
- Instruction শেষ হলে, Pointing register এক ধাপ বাড়ে, অর্থাৎ পরবর্তী instruction address এ চলে যায়।
- Loop বা condition থাকলে সেটা plugboards বা বিশেষ কার্ডে আগে থেকেই সেট করে দিতে হতো।
🛠️ Note:
- তখন কোনো operating system ছিল না। সব কিছু manually করতে হতো।
- RAM আজকের মতো উন্নত ছিল না; বরং ছিল একটি সীমিত মেমোরি ইউনিট।
- পুরো কাজটি ছিল ধীর ও খুবই টেকনিক্যাল।
CPU = Register Set (ডেটা রাখে) + Processing Unit (ডেটা প্রসেস করে) এবং Processing Unit = ALU + Control Unit
💡 The Idea of Operating System
🕰️ ১৯৪০ - ৫০ দশকে, কম্পিউটারে প্রতিটি প্রোগ্রাম manually চালাতে হতো - punch card, আলাদা কোড, অনেক সময়।
🎯 সমাধান :
"একটা সফটওয়্যার থাকুক, যা প্রোগ্রাম চালানোসহ সব কাজ নিজে করবে" - এটাই Operating System।
প্রথম দিকে OS শুধু প্রোগ্রাম চালাত, পরে I/O, memory, file, security management যুক্ত হয়।
⚙️ OS এর Pointing Register (Program Counter) ব্যবহার করে Program Execution
💡 Pointing Register (Program Counter aka PC)
- CPU-র একটি register।
- পরবর্তী যেই instruction execute হবে, তার address রাখে।
👣 Program Execution Steps:
- Computer On -> OS প্রথমে HDD থেকে RAM এ Load হয়
- OS sets up -> Hardware, memory, File System ইত্যাদি
- একটি Program execute -> Click app icon
- OS সেই Program টি HDD থেকে খুঁজে বের করে এবং RAM এ লোড করে
- OS এরপর Pointing Register কে program এর first instruction address সেট করে দেয়
- CPU সেই address থেকে instruction -> fetch -> decode -> execute করতে শুরু করে
➡️ প্রতিটি Instruction শেষ হওয়ার পর, Pointing Register নিজে থেকেই পরবর্তী address update হয়। যদি কোনো loop, function call বা condition থাকে, তাহলে Pointing Register সেই অনুযায়ী নতুন address এ jump করে।
🧬 Evolution of Operating System
🕰️ Early Stages (1940s-1960s):
🔹 1st Generation: Batch Processing Systems:
- প্রথমদিকে কম্পিউটার OS ছাড়াই কাজ করত, প্রোগ্রাম manually load করতে হতো।
- GM-NAA I/O (1956) ছিল First Operating System, যা
IBM 704
এর জন্য input/output ম্যানেজ করত।
🔹 2nd Generation: Multiprogramming & Timesharing:
- Multiprogramming: CPU একাধিক প্রোগ্রামের মাঝে কাজ ভাগ করে efficiency বাড়ায়।
- Time-sharing systems (যেমন: CTSS, Multics): একাধিক ব্যবহারকারী একসাথে কম্পিউটারের সাথে কাজ করতে পারে।
🖥️ The Rise of User-Friendly Interfaces (1970s-1990s):
🔹 3rd Generation: Graphical User Interfaces (GUIs) Apple Macintosh ও Microsoft Windows. Graphical User Interface (GUI) চালু করে, যা কম্পিউটারকে সহজ করে তোলে।
🔹 Unix ও Personal Computers
- Unix: সহজ, বহনযোগ্য ও multitasking সাপোর্টের জন্য জনপ্রিয়।
- 🏛️ History:
- 📅 1970 সালে AT&T Bell Labs এ Ken Thompson ও Dennis Ritchie Unix তৈরি করেন।
- 🧪 এটি C programming language ব্যবহার করে লেখা হয়, যা একে আরও বহনযোগ্য করে তোলে।
- 📚 Unix থেকে জন্ম নেওয়া জনপ্রিয় OS:
- Linux 🐧
- Mac OS 🍎
- BSD, Solaris ইত্যাদি
- 🏛️ History:
- CP/M, PC-DOS: ব্যক্তিগত কম্পিউটারের জন্য সহজ Operating System।
🔹 Linux ও উন্নত GUI
- Linux: Open source OS হিসেবে জনপ্রিয় হয়।
🔹 Windows ও Mac OS
- GUI আরও উন্নত করে।
📱 Modern Era (2000s-Present):
🔹 Mobile & Cloud Computing iOS, Android: মোবাইল OS বাজারে আধিপত্য বিস্তার করে।
Cloud ও Virtualization প্রযুক্তি কম্পিউটিংকে নতুন রূপ দেয়।
🔹 AI Integration AI, Machine Learning, Quantum Computing OS কে আরও বুদ্ধিমান ও অভিযোজিত করে তুলছে।
📌 Key Milestones:
Year | Events |
---|---|
1990 | Windows 3.0 – GUI, computing experience এ ব্যাপক পরিবর্তন আনে |
1995 | Windows 95 – Taskbar, Start Menu ও Plug-and-Play |
2009 | Windows 7 – Enhanced features, speed, and resource usage |
2012 | Windows 8 – Metro Interface, significant revamp |
[Author: @nazma98 Date: 2025-06-09 Category: interview-qa/class-wise ]
Class-34 : 🧩 Breaking The CPU and Process
🧠 Central Processing Unit (CPU)
- The brain of the computer
- Process instructions
CPU এর ২টি প্রধান অংশ হলো:
1. Processing Unit (PU)
- Arithmetic Logic Unit(ALU) + Control Unit(CU) থাকে।
2. Register Set
- Data ও Instructions সাময়িক রাখা হয়।
- Processing Unit এর কাজ সহজ করতে সাহায্য করে।
🔹 Register Set
রেজিস্টার নাম | পূর্ণরূপ / বর্ণনা | কাজের ধরন |
---|---|---|
SP | Stack Pointer | stack এর Top কে point করে |
BP | Base Pointer | Stack frame এর base কে point করে |
IR | Instruction Register | বর্তমানে execute হওয়া instruction রাখে |
PC | Program Counter | পরবর্তী instruction address ধরে রাখে |
General Purpose Registers | (যেমন AX, BX, CX, DX) | Data transfer, calculation ইত্যাদিতে ব্যবহৃত |
🗄️ General Purpose Registers
Register | Size | Description | Typical Use |
---|---|---|---|
AL | 8-bit | Lower 8 bits of AX | store data during arithmetic, logic, or data transfer operations |
BL | 8-bit | Lower 8 bits of BX | General-purpose data storage |
CL | 8-bit | Lower 8 bits of CX | Loop counters, shift/rotate counts |
DL | 8-bit | Lower 8 bits of DX | I/O operations, data storage |
🧮 Registers AL, BL, CL, DL in x86 Architecture
AL, BL, CL, এবং DL respective general-purpose register এর lower 8 bits কে represent করে। CPU architecture এর ওপর ভিত্তি করে এগুলো 16-bit, 32-bit, এবং 64-bit হয়।
8-bit | 16-bit | 32-bit | 64-bit | Description |
---|---|---|---|---|
AL | AX | EAX | RAX | Accumulator register family |
BL | BX | EBX | RBX | Base register family |
CL | CX | ECX | RCX | Count register family (used for loops, shifts) |
DL | DX | EDX | RDX | Data register family |
🏛️ Register Hierarchy
Register | 64-bit part | 32-bit part | 16-bit part | 8-bit high | 8-bit low |
---|---|---|---|---|---|
RAX | RAX | EAX | AX | AH | AL |
RBX | RBX | EBX | BX | BH | BL |
RCX | RCX | ECX | CX | CH | CL |
RDX | RDX | EDX | DX | DH | DL |
⚙️ Control Unit (CU) executes a program stored on a HDD
💾 Program যখন HDD এ থাকে
- Program file → HDD এ থাকে
- Direct access → Slow
⚡ RAM এ Load
- Operating System → Program, HDD থেকে RAM এ নিয়ে আসে → Program Load / Fetch
🚀 Execution শুরু
- Control Unit (CU) → RAM থেকে Program এর First memory address নেয়
- memory address → Program Counter (PC) এ set করা হয়
📥 CU RAM থেকে Instruction Fetch
- CU → PC থেকে memeory address নিয়ে RAM থেকে Instruction fetch করে
- Instruction → Instruction Register (IR) এ store হয়
⚙️ Decode & Execute
- CU → IR এর Instruction কে Decode করে
- CU → ALU/অন্যান্য ইউনিটকে কাজ করতে নির্দেশ দেয়
- PC → পরের Instruction memory address update হয়
⚙️ Go Program Execution Flow by CPU
🧠 Go প্রোগ্রাম রান
go run main.go
→ Go compiler → binary executable file- CPU, load এবং execute করে → binary executable file
📦 Memory Division
Code Segment
→const
,func
/ instructions (যা পরিবর্তন হবে না / Read only)Data Segment
→ global variableStack
→ function calls & local variableHeap
→ dynamic memory
🧱 Stack Frame
main()
(বা অন্য কোনো function) call হলে Stack Frame create হয়। Stack Frame এ থাকে:
- Local variables (
a := 10
) - Return address (function শেষে কোথায় return)
- Function parameters (যদি থাকে)
- Saved registers (CPU registers)
📊 Stack Frame Structure
↑ Higher memory address
---------------------
| Return Address | ← main() call
--------------------
| Old Base Pointer | ← BP
--------------------
| Local variable y |
| Local variable x | ← SP (grows downwards)
--------------------
↓ Lower memory address
Stack pointer (SP) এবং Base pointer (BP) হল CPU registers, যা stack frame manage করতে ব্যবহৃত হয়।
💡 Process
-
Program execution শুরু হলে → process create হয়
-
Process → Program execution সাহায্য করে
-
এর ভেতরে থাকে → Code Segment, Data Segment, Stack, Heap, এবং CPU রেজিস্টার
-
Process Dead বা Terminated → OS সমস্ত memory ও resources (RAM, file, etc.) free করে
| অংশ | | -------------------- | | Code Segment | | Data Segment | | Heap | | Stack | | Registers | | Program Counter (PC) | | File Descriptors |
[Author: @nazma98 Date: 2025-06-11 Category: interview-qa/class-wise ]
🧠 CPU Structure and Stack Frame Execution Notes
🔹 CPU: Two Core Components
-
Processing Unit
- Arithmetic Logic Unit (ALU): সব ধরনের গাণিতিক (arithmetic) এবং যৌক্তিক (logical) operations করে থাকে।
- Control Unit (CU): CPU এর মধ্যে গাণিতিক (arithmetic) এবং যৌক্তিক (logical) operations পরিচালনা করে, input/output এবং instruction decoding কীভাবে হবে তা কন্ট্রোল করে।
-
Register Set
- Program Counter (PC): পরবর্তীতে যেই Instruction টি execute হবে তার address ধারণ করে ।
- Stack Pointer (SP): মেমরিতে বর্তমানে যে stack আছে তার Top কে point করে।
- Base Pointer (BP): বর্তমান stack frame এর base কে point করে।
- Instruction Register (IR): এই মুহূর্তে যে instruction টি execute হচ্ছে সেটি রাখে।
- General Purpose Registers: Data manipulation যেমন arithmetic ও logical operation এবং data movement এর জন্য অস্থায়ীভাবে data রাখে।
🔹 Bits and Bytes
- 8-bit = 1 byte
- 16-bit = 2 bytes
- 32-bit = 4 bytes
- 64-bit = 8 bytes
Memory addressing = ( 2^n )
🔹 RAM Addressing on 32-bit System
Memory cell 4 bytes করে বাড়তে থাকে। (since 32-bit = 4 bytes):
Address: 0 4 8 12 16 20 24 ...
[ ] [ ] [ ] [ ] [ ] [ ] [ ]
🔹 OS, RAM, and Process Execution
- OS executable code আনে HDD থেকে → RAM এ লোড করে
- OS একটি process create করে
- RAM process memory কে কয়েকটি ভাগে ভাগ করে:
- Code Segment (constants এবং instructions এর জন্য)
- Data Segment (global/static variables এর জন্য)
- Stack (function calls এবং local variables এর জন্য)
- Heap (dynamically memory allocate করার জন্য)
🔹 Stack Frame in Function Call
- OS, SP এবং BP set করে দেয়।
- SP < BP ( SP memory তে lower address কে point করে)।
Stack Frame Layout:
[ Local Variables ] <-- SP (grows downward)
[ Old Base Pointer ]
[ Return Address ]
[ Parameters (right→left)] <-- BP
- Return Address সাধারণত রাখা হয়
BP + 4
(32 bit computer),BP + 8
(64 bit computer) etc. ( Base pointer এর ঠিক উপরে ) - BP ব্যবহার করে CPU সহজেই যা access করতে পারে:
- Function parameters
- Return address
- Local variables
🔹 Stack Frame Exit
- Stack frame যা pop করে (সরিয়ে ফেলে):
- Local variables
- Old BP value register set এর BP তে restore হয়
- SP reset হয়
- Execution, Return Address কে follow করে সেখানে jump করে
Final Condition:
BP == SP => Stack Frame Close হয়ে যায়
🧭 Diagram: Stack Frame Example (32-bit)
Memory Address ↓
+----------------------+ <- BP
| Parameter 1 |
+----------------------+
| Parameter 2 |
+----------------------+
| Return Address | <- BP + 4
+----------------------+
| Old Base Pointer | <- BP + 8
+----------------------+
| Local Variable A | <- SP
+----------------------+
Stack grows downward ↓
✅ Summary
- CPU mainly Processing Unit এবং Register Set এ বিভক্ত।
- Stack Frame function call handling এর জন্য responsible থাকে।
- Base Pointer (BP) একটি fixed reference point হিসেবে কাজ করে।
- Stack Pointer (SP) function execution এর সময় move করতে থাকে।
- একটি function Return করলে BP এবং SP reset হয়ে যায়।
debugging, compiler design, এবং low-level programming এর জন্য stack frames বুঝা অত্যন্ত প্রয়োজনীয়।
Class 36: Context Switching, PCB, Concurrency
context switching কী ?
Context Switching মানে হল, CPU একটা প্রসেস রেখে আরেকটা প্রসেস চালানো শুরু করে।
ঠিক যেমন ক্লাসে তুমি ম্যাথ করছিলে, হঠাৎ টিচার বলল “এবার ইংরেজি করো” তখন তুমি ম্যাথের খাতা বন্ধ করে ইংরেজির খাতা খুললে।
এই খাতা বদলানোই হলো Context Switch! 🧑🏫
🧱 কিভাবে কাজ করে?
- CPU এখন একটা প্রসেস (ধরো গেম) চালাচ্ছে।
- হঠাৎ OS বলে “এই তো, ভিডিও কল আসছে! আগে এটাকে চালাও।”
- তখন CPU গেমের অবস্থা (registers, state) একটা PCB-তে রেখে দেয়।
- এরপর নতুন প্রসেস (ভিডিও কল) এর অবস্থা PCB থেকে নিয়ে চালানো শুরু করে।
এভাবেই CPU বারবার প্রসেস বদলায়।
🎯 কেন দরকার?
- অনেক কাজ একসাথে করার জন্য
- যেই কাজটা এখন বেশি দরকার, সেটাকে চালানোর জন্য
- RAM বা CPU কে সঠিকভাবে ব্যবহার করার জন্য
🔍 Process Control Block (PCB)
কম্পিউটার যখন একসাথে অনেকগুলো প্রোগ্রাম চালায় (যেমন: গেম, মিউজিক, ব্রাউজার), তখন প্রতিটা প্রোগ্রাম একেকটা আলাদা Process (প্রসেস) হয়ে চলে।
এই প্রসেসগুলোকে চিনে রাখা, মনিটর করা আর নিয়ন্ত্রণ করার জন্য অপারেটিং সিস্টেম (OS) ব্যবহার করে একটা বিশেষ জিনিস যেটার নাম Process Control Block (PCB)।
🧠 PCB কী ❓
PCB হলো একটি ছোট্ট তথ্যের বাক্স (Data Structure) যেখানে একটি প্রসেস সম্পর্কিত সব দরকারি তথ্য জমা থাকে।
একে তুমি ভাবতে পারো, প্রতিটা প্রসেসের আইডি কার্ড বা রিপোর্ট কার্ড হিসেবে।
কেন PCB দরকার ❓
যখন অনেকগুলো প্রসেস একসাথে চলছে, তখন অপারেটিং সিস্টেমকে প্রতিটা প্রসেস সম্পর্কে জানতে হয়
- কে কোন জায়গা পর্যন্ত কাজ করেছে?
- কে এখন রানিং মোডে?
- কার কী রিসোর্স লাগছে?
- কতটুকু মেমোরি বা CPU লাগবে?
এই সব প্রশ্নের উত্তর থাকে PCB-তে।
আর যখন প্রসেস পরিবর্তন করতে হয় (একটা থেকে আরেকটাতে যেতে হয়), তখন PCB ছাড়া OS কিছুই করতে পারত না!
PCB-তে কী কী থাকে ❓
🧩 অংশ | 🎯 কাজ |
---|---|
Process ID (PID) | প্রতিটা প্রসেসের ইউনিক নাম বা নম্বর |
Process State | এখন প্রসেসটা কী অবস্থায় আছে (Ready, Running, Waiting) |
Program Counter | পরবর্তী কোন ইনস্ট্রাকশন চলবে সেটা দেখায় |
CPU Registers | CPU-তে চলা হিসাবের শেষ অবস্থান |
Memory Management Info | প্রসেস কোথায় কোথায় RAM ব্যবহার করছে |
I/O Info | ইনপুট-আউটপুট ডিভাইসের সাথে সম্পর্কিত তথ্য |
Accounting Info | প্রসেস কত সময় চালানো হলো, কে চালালো ইত্যাদি |
🌀 উদাহরণ দিয়ে বোঝা যাক:
ধরো তুমি একটি গেম খেলছো, আর তোমার ভাই ইউটিউবে ভিডিও দেখছে।
➡️ গেমটা এক ধরনের প্রসেস, ইউটিউব আরেকটা।
➡️ অপারেটিং সিস্টেম এই দুই প্রসেসকে আলাদা করে রাখতে PCB ব্যবহার করে।
➡️ প্রতিটা গেম/ভিডিও প্রসেসের জন্য আলাদা PCB থাকে যখন তুমি গেম থেকে বের হয়ে ইউটিউবে গেলে, তখন OS:
- গেমের সব তথ্য PCB-তে রেখে দেয়
- ইউটিউবের তথ্য PCB থেকে নিয়ে কাজ শুরু করে
এটাকে বলে Context Switch।
🎯 PCB কী কী করে ❓
✅ প্রসেসকে আলাদা করে চিনে রাখে
✅ প্রসেস চলাকালীন অবস্থা রেকর্ড রাখে
✅ প্রসেসের মেমোরি, CPU এবং I/O ব্যবস্থাপনা করে
✅ প্রসেস পরিবর্তনের সময় আগের কাজ মনে রাখে
✅ প্রসেস চলার হিসাব রাখে (অ্যাকাউন্টিং)
📌 মনে রাখার মতো বিষয়:
- PCB = প্রসেসের আইডি কার্ড + রিপোর্ট কার্ড + ফাইল
- এটা অপারেটিং সিস্টেমের জন্য সবচেয়ে দরকারি টুল
- প্রতিটা প্রসেসের জন্য একটা আলাদা PCB থাকে
- PCB ছাড়া প্রসেস ম্যানেজমেন্ট সম্ভব নয়
📋 Example :
-------------------------------------
| Process ID : 101 |
| State : Running |
| Program Counter : 0x0034 |
| Registers : AX=5, BX=2 |
| Memory : 200MB |
| I/O Devices : Keyboard |
| User Time : 0.05 sec |
------------------------------------
⬆️
Process Control Block
শেষ কথা:
- কম্পিউটার যেভাবে অনেক কাজ একসাথে করে,
- ঠিক তেমনি PCB-এর মাধ্যমে প্রতিটা কাজ (প্রসেস) আলাদা করে হ্যান্ডেল করে।
- এটা অপারেটিং সিস্টেমের অদৃশ্য সেনাপতি!
⏱️ Concurrency একসাথে অনেক কাজ!
👶 সহজভাবে বললে:
Concurrency মানে হলো, CPU যেন একসাথে অনেকগুলো কাজ করছে এমন একটা ধোঁকা দেয়।
ধরো তোমার মা একসাথে ভাত রান্না করছে, ডাল দিচ্ছে, আবার ফোনেও কথা বলছে মানে কাজগুলো একসাথে চলছে।
একসাথে সব কাজ না করলেও, অল্প অল্প করে সবকিছু সামলাচ্ছে। এটাকেই বলে Concurrency।
👨💻 কম্পিউটারে কিভাবে হয়?
- CPU একসাথে অনেক Process চালায় না, কিন্তু একটা একটু চালায়, তারপর আরেকটা, তারপর আবার প্রথমটা এভাবে।
- এতে মনে হয়, সবকিছু একসাথে চলছে।
📌 মনে রাখো:
বিষয় | ব্যাখ্যা |
---|---|
Context Switching | CPU এক প্রসেস থেকে আরেকটায় যায় |
PCB | প্রতিটি প্রসেসের গুরুত্বপূর্ণ তথ্য যেখানে রাখা হয় |
Concurrency | CPU একসাথে অনেক প্রসেস চালাচ্ছে এমন একটা অভিজ্ঞতা দেয় |
[Author : @shahriar-em0n Date: 2025-06-05 Category: interview-qa/class-wise ]
🧠 Parallelism vs Concurrency
১. Concurrency
Concurrency এমন একটি প্রক্রিয়া যেখানে CPU একসাথে অনেকগুলো কাজ একইসাথে run করছে এমন একটি illusion তৈরি করা, এটি এমনভাবে কাজ করে যেন সবগুলো কাজ একইসাথে চলছে অর্থাৎ ব্যবহারকারীর চোখে এটি যেন একসাথে অনেক কাজ হচ্ছে এমন একটি illusion তৈরি করে।
🛠 উদাহরণ :
YouTube অ্যাপ চালানোর সময় তুমি দেখতে পারো:
- ভিডিও প্লে হচ্ছে
- কমেন্ট লোড হচ্ছে
- বিজ্ঞাপন আসছে
- স্ক্রল করলে নতুন ভিডিও সাজেশন আসছে
সবকিছুই একসাথে ঘটছে বলে মনে হয়, কিন্তু মূলত এই কাজগুলো context switching এর মাধ্যমে একে একে execute হচ্ছে।
✅ মূল বৈশিষ্ট্য:
- একসাথে অনেক কাজ handle করা হয়
- CPU এক সময়ে একটিই কাজ করে, কিন্তু দ্রুত context switch করে
- Single-core CPU-তেও কাজ করে
২. Parallelism
Parallelism বোঝায় একাধিক কাজ একই সময়ে, একাধিক CPU বা processor/core ব্যবহার করে execute হওয়া। প্রতিটি কাজ আলাদা processor/core দ্বারা একসাথে চালানো হয়।
🛠 উদাহরণ :
ধরো, তুমি Adobe Premiere Pro তে ভিডিও এক্সপোর্ট দিচ্ছো একি সময়ে
- একটি core ভিডিও প্রসেস করছে
- অন্য core অডিও রেন্ডার করছে
- আরেকটি core এফেক্ট প্রসেস করছে
এই কাজগুলো processor/CPU multiple core দ্বারা একসাথে চলায় যাতে রেন্ডারিং দ্রুত সম্পন্ন হয়। এটি Parallelism।
✅ মূল বৈশিষ্ট্য:
- একাধিক কাজ একই সময়ে সত্যিকারের parallel চলে
- Multi-core processor দরকার
- সময় বাঁচে এবং efficiency বাড়ে
৩. তুলনামূলক পার্থক্য
বিষয় | Concurrency | Parallelism |
---|---|---|
কাজের ধরন | একাধিক কাজ context switch করে execute হয় | একাধিক কাজ একসাথে চলতে থাকে |
প্রয়োজনীয়তা | Single-core CPU-তেও সম্ভব | Multi-core CPU প্রয়োজন |
বাস্তব উদাহরণ | YouTube অ্যাপের বিভিন্ন ফিচার একসাথে চলা | Video rendering-এ একাধিক core কাজ করে |
উদ্দেশ্য | অনেক কাজকে একসাথে handle করা | কাজগুলো দ্রুত এবং একযোগে শেষ করা |
Task Execution Style | Interleaved (ক্রমাগত পালাক্রমে) | Simultaneous (একসাথে একযোগে) |
৪. সংক্ষেপে:
- Concurrency হলো কাজগুলোকে একসাথে handle করার কৌশল, যেখানে একসাথে অনেক কিছু ঘটলেও, CPU এক সময়ে একটিই কাজ করে।
- Parallelism হলো সত্যিকারের একসাথে অনেক কাজ করা, যেখানে প্রতিটি কাজ ভিন্ন ভিন্ন processor/core দ্বারা চলে।
[Author : @shahriar-em0n Date: 2025-06-09 Category: interview-qa/class-wise ]
Class 38 - Thread
🧵 Thread কী?
- Thread হল কোন process এর একটি execution unit.
- একটি process creation এর সাথে সাথে by default একটি thread create হয় যাকে main thread ও বলা হয়।
- Thread মূলত RAM এ load করা instruction/program code গুলো execute করে থাকে।
🧠 Thread কোথায় থাকে?
User software/program এ double click করে
⬇️
RAM এ লোড হওয়া program এর binary executable code load হয়
⬇️
OS একটি process create করে
⬇️
default thread create হয়
- Thread কে process এর একটি অংশ বলা যায়।
- Process creation এর শুরুতে thread এবং process একই থাকে।
- Process is container, thread is executor
🔍 Thread কে Virtual Process কেন বলা হয়?
- New Process create ➡️ Default Thread Create হয়
- Thread এর Code Segment, Data Segment, Stack, Heap ইত্যাদি থাকে ➡️ Process এর অনুরূপ
- Process এর মতোই behave করে থাকে।
- Logical Process বলা হয়।
🧶🔄 Multi-threading
একটি process এর মধ্যে অনেকগুলো কাজ বা functionality execute করার জন্য, OS ওই process এর ভেতরে একাধিক execution unit তৈরি করে, যেগুলো একসাথে কাজ করে, তখন তাকে Multi-threading
বলে।
✨ একই Process এর অন্তর্ভুক্ত Multiple Threads এর কিছু Characteristics
- প্রতিটি Thread এর নিজস্ব CPU state (যেমন: Register, Program Counter) এবং Stack থাকে।
- সব Thread একই Process এর code section, data section এবং OS resources (e.g. open files and signals) share করে।
- প্রতিটি Thread এর নিজস্ব TCB (Thread Control Block) থাকে।
- Thread গুলো lightweight হওয়ায় context switching দ্রুত হয়।
- একে অপরের সাথে সহজে Data শেয়ার করতে পারে → Fast Communication সম্ভব।
- এক Thread এ bug থাকলে পুরো process crash করতে পারে।
- Data sharing এর জন্য synchronization দরকার (mutex/semaphore)।
🧵 Visualization: Multi-threading Inside a Process
+-----------------------------+
| Process |
| (e.g., Media Player App) |
| |
| +-----------------------+ |
| | Thread 1 | | --> Play Audio
| +-----------------------+ |
| |
| +-----------------------+ |
| | Thread 2 | | --> Display Video
| +-----------------------+ |
| |
| +-----------------------+ |
| | Thread 3 | | --> Handle User Input
| +-----------------------+ |
| |
+-----------------------------+
🔍 Explanation
Process হচ্ছে একটি চলমান প্রোগ্রাম (যেমন: VLC Player)। সেই প্রোগ্রামের ভেতরে একাধিক Thread কাজ করছে। যেমন:
- 🎵 Thread 1: অডিও প্লে করছে
- 📺 Thread 2: ভিডিও দেখাচ্ছে
- 🎮 Thread 3: ইউজারের কীবোর্ড/মাউস ইনপুট নিচ্ছে
সব thread মিলে একটি process এর কাজকে দ্রুত ও কার্যকর করে।
🔄 Context Switching in Thread
- Thread ➡️ একটি নির্দিষ্ট কাজ/functionality এর জন্য দায়ী
- Process দ্রুত execute করার লক্ষ্যে ➡️ OS, multiple thread create করে
- Program Counter একটি নির্দিষ্ট সময়ে শুধু একটি thread এর instruction address ধরে রাখতে পারে ➡️ CPU একসাথে সব থ্রেড চালাতে পারে না
- CPU কিছু সময় একটি thread execute করে ➡️ একটি thread এর সময় শেষ বা thread blocked (যেমন: I/O wait)
- OS সেই thread এর current state (registers, stack pointer, program counter) সংরক্ষণ করে ➡️ TCB (Thread Control Block)
- এরপর OS অন্য thread এর state load করে
- এই পুরো প্রক্রিয়াটিকেই বলা হয় ➡️ Thread Context Switching
Thread Pool 🧵🧵
Thread pool হলো আগেই তৈরি করা কিছু Thread, যেগুলো Process এ বসে থাকে আর কাজ এলে তা করে ফেলে। প্রতিবার নতুন Thread না বানিয়ে আগের তৈরি Thread ব্যবহার করায় সময় ও রিসোর্স বাঁচে; বিশেষভাবে ছোট ও অনেক কাজ থাকলে এটা খুবই উপকারী।
⚙️ Process Vs Thread 🧵
Feature | Process | Thread |
---|---|---|
🔒 Resource Isolation | প্রতিটি Process এর নিজস্ব memory ও resources থাকে | একই Process এর মধ্যে সব Thread একই memory ও resources শেয়ার করে |
🔄 Communication | জটিল; Inter-Process Communication (IPC) mechanisms প্রয়োজন হয় | সহজ; shared memory ব্যবহার করে Thread গুলো একে অপরের সাথে যোগাযোগ করে |
⚡ Overhead | Process তৈরি ও পরিচালনার জন্য বেশি overhead লাগে | Thread তৈরি ও পরিচালনা তুলনামূলকভাবে কম overhead |
⏱️ Concurrency | Concurrency সম্ভব, তবে cost বেশি | একই Process এর মধ্যে concurrency অর্জনে বেশি কার্যকর |
🛡️ Isolation | এক Process অন্য Process এর memory তে সরাসরি প্রবেশ করতে পারে না | Threads একে অপরের উপর প্রভাব ফেলতে পারে, কারণ তারা memory শেয়ার করে |
📌 Example | প্রতিটি browser tab আলাদা Process হিসেবে চলে | rendering, networking, JavaScript execution ইত্যাদি আলাদা Thread এ হয় |
[Author: @nazma98 Date: 2025-06-02 Category: interview-qa/class-wise ]
💐 Class 39 - Vogus Data Types
🔢 Signed Integer Type
Golang এ int8
, int16
, int32
, এবং int64
হল signed integer types যাদের specific bit size থাকে। নিচে এ সম্পর্কে বিস্তারিত দেওয়া হল:
Type | Size | Range |
---|---|---|
int8 | 8 bit / 1 byte | -128 to 127 |
int16 | 16 bit / 2 bytes | -32,768 to 32,767 |
int32 | 32 bit / 4 bytes | -2,147,483,648 to 2,147,483,647 |
int64 | 64 bit / 8 bytes | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
Go Runtime handles how to store each type of variable
🧠 int type কী?
Golang এ int
টাইপের কোন নির্দিষ্ট সাইজ নেই। এটি Computer architecture এর উপর নির্ভর করে:
32-bit computer → int = 32 bit
64-bit computer → int = 64 bit
🌷 Example
package main
import "fmt"
func main() {
var a int8 = 5
fmt.Println(a)
}
🖼️ Visualization of storing int8
in 32-bit computer
Decimal to Binary (8-bit signed):
5 in binary = 00000101
(as int8
)
🧮 32-bit Memory Cell Visualization for int8 a = 5
Bits | 31 ... 8 (Unused/Padding) | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|
Bit Values | 00000000 00000000 00000000 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
📌 Tips:
- Memory save →
int8
,int16
- Performance / Process easy →
int
বাint32
- সব সময় Range এর মধ্যে data থাকবে কিনা তা আগে ভাবুন।
📦 Unsigned Integer Type
Golang এ unsigned int - uint
টাইপ হলো এমন সংখ্যা যা কখনোই ঋণাত্মক (negative) হতে পারে না।
- 👉 শুধুমাত্র ধনাত্মক সংখ্যা (positive) বা শূন্য (0) নিতে পারে।
Type | Size | Range |
---|---|---|
uint8 | 8 bit / 1 byte | 0 to 255 |
uint16 | 16 bit / 2 bytes | 0 to 65,535 |
uint32 | 32 bit / 4 bytes | 0 to 4,294,967,295 |
uint64 | 64 bit / 8 bytes | 0 to 18,446,744,073,709,551,615 |
🧪 Example
package main
import "fmt"
func main() {
var age uint8 = 25
fmt.Println(age)
}
🧠 uint type
Golang এ uint
টাইপের কোন নির্দিষ্ট সাইজ নেই। এটি Computer architecture এর উপর নির্ভর করে:
32-bit computer → uint = 32 bit
64-bit computer → uint = 64 bit
🔢 Float Type
দশমিক সংখ্যা (fractional numbers) রাখার জন্য float
টাইপ ব্যবহার করা হয়। যেমনঃ 3.14
, -2.75
, 0.001
।
🧪 Golang এ Float দুই types:
type | size | Precision |
---|---|---|
float32 | 32-bit | প্রায় ৭ দশমিক ঘর পর্যন্ত সঠিক |
float64 | 64-bit | প্রায় ১৫-১৭ দশমিক ঘর পর্যন্ত সঠিক |
শুধু float নামে কোনো type নেই।
🧪 Example
package main
import "fmt"
func main() {
var x float32 = 3.1415
var y float64 = 2.7182818284
fmt.Println("x =", x)
fmt.Println("y =", y)
}
📌 Note: Golang এ দশমিক সংখ্যা লিখলে সেটা default
float64
হয়।
f := 1.5 // float64
🔢 Boolean Type
Boolean টাইপ bool
শুধু দুইটি value রাখতে পারে:
true
false
🌸 Example
package main
import "fmt"
func main() {
var isActive bool = true
fmt.Println("isActive:", isActive)
}
bool
type memory তে সঠিকভাবে 1 bit নয়, বরং 1 byte (8 bits) জায়গা নেয়।
✳️ Byte Type
- alias for
uint8
- 8 bits per character
package main
import "fmt"
func main() {
var a byte = 65
fmt.Println(a) // Output: 65
fmt.Println(string(a)) // Output: A
}
🔎 Note:
byte
শুধু0
থেকে255
পর্যন্ত value রাখতে পারে।- character encoding এর সাথে কাজ করতে গেলে byte খুবই দরকারি।
🧮 Rune
- alias for
int32
(unicode point) -32 bits
/4 bytes
- Unicode character রাখে
🌻 Example
package main
import "fmt"
func main() {
r := '❤'
fmt.Printf("%c\n", r) // Output: ❤
}
🔢 Format Specifiers Table
Format | Type | Description | Example |
---|---|---|---|
%d | int | Decimal integer | 42 |
%f | float | Decimal float (default precision) | 3.14 |
%.2f | float | Float with 2 decimal points | 3.14 |
%s | string | String | "Hello" |
%t | bool | true/false | true |
%c | rune | Character (Unicode) | 🙂 |
%U | rune | Unicode format | U+1F642 |
%v | any | Default value (auto detect) | true , 42 , etc. |
%T | any | Type of the variable | int , string , etc. |
🌻 Example
package main
import "fmt"
func main() {
var a int8 = -128
var x uint8 = 255
var j float32 = 10.23343
var k float64 = 10.4455235
var flag bool = true
var s string = "The sky is beautiful"
r := '❤'
fmt.Printf("%c\n", r) // Output: ❤
fmt.Printf("%d\n", a) // Output: -128
fmt.Printf("%d\n", x) // Output: 255
fmt.Printf("%.2f\n", j) // Output: 10.23
fmt.Printf("%.5f\n", k) // Output: 10.44552
fmt.Printf("%v\n", flag) // Output: true
fmt.Printf("%s\n", s) // Output: The sky is beautiful
fmt.Printf("** Type of variable s = %T", s) // Output: string
}
[Author: @nazma98 Date: 2025-06-05 Category: interview-qa/class-wise ]
🌀 Golang এর defer
: ভিতরের স্ট্যাক, রিটার্ন ফাঁদ, এবং বাস্তব উদাহরণে ডুব
"
defer
মানে হচ্ছে — তোমার কাজ হবে, কিন্তু পরে হবে।"
Go-এর defer
হলো এমন একটা ফিচার যেটা clean code লেখার জন্য অনবদ্য, কিন্তু ভুল বুঝলে subtle bug এর উৎস। চলুন আজ defer
-কে সম্পূর্ণভাবে বোঝার চেষ্টা করি — তার পেছনের স্টোরি সহ।
🔸 defer
কি?
defer
একটি কিওয়ার্ড যেটি কোন ফাংশনের শেষ মুহূর্তে অন্য একটি ফাংশনকে চালাতে বলে। মূলতঃ এটি ব্যবহৃত হয় cleanup কাজের জন্য — যেমন:
file.Close()
unlock()
recover()
- লগিং
🎯 কীভাবে কাজ করে defer
?
Go কম্পাইলার defer
স্টেটমেন্টগুলোকে compile time এ detect করে এবং runtime এ একটি internal stack এ রেখে দেয়। যখন function return করে, তখন এই stack থেকে একে একে ফাংশনগুলো পিছন থেকে সামনে (LIFO) চালানো হয়।
func main() {
defer fmt.Println("A")
defer fmt.Println("B")
fmt.Println("C")
}
🖨️ Output:
C
B
A
📌 defer
গুলো পিছনের দিকে যায় কারণ: Go stack এ push
করে defer গুলোকে → পরে reverse করে pop
করে।
🔧 পিছনের দিক থেকে ব্যাখ্যা (Behind-the-scenes)
func sayHello() {
defer log("1")
defer log("2")
defer log("3")
}
Go internally কিছুটা এরকম করে:
deferStack := []func(){}
deferStack = append(deferStack, log("1"))
deferStack = append(deferStack, log("2"))
deferStack = append(deferStack, log("3"))
for i := len(deferStack)-1; i >= 0; i-- {
deferStack[i]()
}
Go runtime defer গুলিকে একটি linked list structure-এ সংরক্ষণ করে, কিন্তু সেটা Stack behavior অনুযায়ী কাজ করে।
🎭 Named Return vs Unnamed Return — defer
এর দুইরকম ব্যবহার
এই হলো defer
এর “দুই মুখো” চরিত্র। 🤹♂️
✅ Named Return Value ব্যবহার করলে:
func example1() (result int) {
defer func() {
result = 99
}()
return 10
}
📌 এখানে result
হল named return variable, তাই defer
যখন চলে, তখন result
এখনও accessible, এবং সেটাকে modify করা যায়।
🖨️ Output:
99
❌ Unnamed Return Value ব্যবহার করলে:
func example2() int {
result := 10
defer func() {
result = 99
}()
return result
}
📌 এখানে return result
বলার সাথে সাথে result এর ভ্যালু রিটার্ন buffer-এ কপি হয়ে যায় — তারপরে defer
চালানো হয়, তাই এর কোনো প্রভাব পড়ে না।
🖨️ Output:
10
🧠 আরও কিছু মন ভোলানো Example
🔄 defer
with loop
func loopDefer() {
for i := 1; i <= 3; i++ {
defer fmt.Println("Deferred:", i)
}
}
🖨️ Output:
Deferred: 3
Deferred: 2
Deferred: 1
📌 প্রতিবার loop এ defer
নতুন করে register হয়। তাই stack অনুযায়ী উল্টোভাবে execute হয়।
📛 Variable Capture Trap (Closure)
func closureDefer() {
for i := 1; i <= 3; i++ {
defer func() {
fmt.Println("Deferred:", i)
}()
}
}
🖨️ Output:
Deferred: 4
Deferred: 4
Deferred: 4
😵💫 কেন?
কারণ closure-এ i
capture হচ্ছে by reference — প্রতিবার একই i এর address!
👉 Fix:
func fixedClosureDefer() {
for i := 1; i <= 3; i++ {
val := i
defer func() {
fmt.Println("Deferred:", val)
}()
}
}
🖨️ Output:
Deferred: 3
Deferred: 2
Deferred: 1
🛠️ Practical Use Cases
- File Handling:
func readFile(path string) error {
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
// read file...
return nil
}
- Mutex Unlock:
mu.Lock()
defer mu.Unlock()
// critical section
- Recover from panic:
func safe() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered:", r)
}
}()
panic("something went wrong")
}
🧾 Key Takeaways (সংক্ষেপে)
বৈশিষ্ট্য | ব্যাখ্যা |
---|---|
Execution order | LIFO (Last In, First Out) |
Internal structure | Linked List with Stack behavior |
Named return | defer can modify it |
Unnamed return | defer can’t modify it |
Variable capture | Closure captures by reference — careful! |
Use cases | File close, Mutex unlock, Panic recovery |
🎁 Bonus: Debug Suggestion
✅ If you're debugging defer
issues:
- Use
go run -gcflags=all="-m"
to see escape analysis. - Print log inside defer to see the order.
- Add named returns if defer needs to modify output.
🧠 শেষ কথা
Go-এর defer
যত ছোট দেখতে, তত গভীর তার আচরণ। একে সঠিকভাবে বোঝা মানে হচ্ছে —
- Cleaner code
- Resource leak রোধ
- কম Bug
শুধু syntax জানলেই হবে না — এর ভিতরের Stack-মাথা, Return-trap, এবং Variable-capture খেলাও বোঝা জরুরি।
🧵 Class 41 : Separate Stack For Separate Thread
🔁 Recap
🧠 Program Execution
- Program execute -> Process create
- Process create -> default একটি thread create (main thread)
- OS (Kernel) -> Thread execute করে
- Thread execute -> Independent task / features
🧪 Example
একটি প্রোগ্রাম যেমন Music Player — তার অনেক গুলো কাজ (functionality) একসাথে চালানো লাগে: যেমন:
- 🎵 Music List দেখানো
- ▶️ Music PLay
- 🎶 বিট/Visualizer দেখানো
এগুলো একসাথে চলতে পারে, কিন্তু একটার কাজ আরেকটাকে আটকে রাখতে পারে না। এই জন্যই Thread ব্যবহার করা হয়।
Program (Process)
│
├── Thread 1 (Main Thread)
│ └── Stack: funcA(), var x, return addr
│
├── Thread 2
│ └── Stack: funcPlay(), var song, return addr
│
└── Thread 3
└── Stack: funcVisual(), var beat, return addr
🧷 Main Function Execution
প্রায় প্রতিটি compiled এবং structured language-এ execution শুরু হয় main() function দিয়ে, কারণ এটি একটি নির্ধারিত entry point যা runtime system বা OS খুঁজে নিয়ে চালায়।
main
function -> stackframe create হয়main()
এর ভিতর অন্য function invoke -> তার জন্য stackframe create হয়- প্রতিটি Stack, একটি Thread এর জন্য বরাদ্দ থাকে
- Stack Execute -> Thread Execute
Stack একটা একটা করে সব function execute করে।
Stack কে Thread execute করে।
🗂️ Thread এবং Stack
একটি Program execute করতে হলে multiple tasks parallely করতে হতে পারে।
এর জন্য দরকার হয় Multiple Threads।
প্রতিটি Thread যখন তৈরি হয়, তখন নিজস্ব Stack memory বরাদ্দ পায়।
এই Stack এ থাকে:
- ফাংশন কলের return address
- Local variables
- Function arguments
💾 Stack কোথায় থাকে
- main thread -> main stack
- Linux -> RAM এ Stack এর জন্য
8MB
allocate হয় - Independent task এর জন্য আলাদা Thread লাগবে -> new Stack -> RAM এ 8MB Storage
- Process এর জন্য -> No. of Thread
*
8MB allcoate হয়- Process এ
10
Thread থাকলে10 * 8 = 80
MB RAM allocated হয়
- Process এ
- Stack, RAM এর যে কোন ফাঁকা জায়গায় থাকতে পারে
- Code Segment, Data Segment, Heap -> সব thread access / use করতে পারে
- Process, main thread বাদে অন্য thread track / execute করে না
- Thread -> Stack এ কোন variable / function না থাকলে -> kernel কে code segment, data segment এ search করতে request করে
🖥️ Kernel
- main thread বাদে অন্য thread -> Kernel create করে
- Thread execute -> Opeating System (Kernel)
- Kernel decide করে -> কোন processor কোন process / thread কে execute করবে
- Kernel track রাখে -> কোন process এর under এ কয়টি thread থাকে
- Kernel (Modern computer) -> execution এর ক্ষেত্রে only thread count রাখে
📌 Code Segment, Data Segment, Stack এর size fixed থাকে। Heap dynamically grow / shrink করতে পারে তাই data, Heap এ বেশি রাখা হয়।
🧠 Operating System core component -> Kernel; Kernel process schedule, concurrency / parallelism handle করে।
🧾 Programming language এর উপর depend করে কীভাবে thread create হবে।
📊 Default Stack Sizes by Platform
OS | Default Stack Size (main thread) | Default Stack Size (new threads) | Notes |
---|---|---|---|
🪟 Windows | 1 MB | 1 MB | Can be changed via linker or CreateThread |
🐧 Linux | 8 MB | 8 MB | Controlled by ulimit -s and pthread_attr_setstacksize() |
🍎 macOS | 8 MB | 512 KB | Main thread gets 8MB, but pthread threads get 512KB by default |
Topic wise
[Author: @mdimamhosen Date: 2025-04-19 Category: interview-qa/arrays Tags: [go, arrays, functions] ]
Arrays in Go
Declaring Arrays
You can declare an array in Go using the following syntax:
var arrayName [size]elementType
Example:
var numbers [5]int
Initializing Arrays
Arrays can be initialized at the time of declaration:
var numbers = [5]int{1, 2, 3, 4, 5}
Or you can use the shorthand notation:
numbers := [5]int{1, 2, 3, 4, 5}
Accessing Array Elements
Array elements are accessed using the index, which starts from 0:
fmt.Println(numbers[0]) // Output: 1
Iterating Over Arrays
You can iterate over arrays using a for
loop:
for i := 0; i < len(numbers); i++ {
fmt.Println(numbers[i])
}
Or using the range
keyword:
for index, value := range numbers {
fmt.Println(index, value)
}
Multidimensional Arrays
Go supports multidimensional arrays. A two-dimensional array is declared as follows:
var matrix [3][3]int
Example:
matrix := [3][3]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
Array of Arrays
You can also create an array of arrays:
var arrayOfArrays [2][3]int
Example:
arrayOfArrays := [2][3]int{
{1, 2, 3},
{4, 5, 6},
}
Passing Arrays to Functions
Arrays can be passed to functions by value, meaning the function receives a copy of the array:
func printArray(arr [5]int) {
for i := 0; i < len(arr); i++ {
fmt.Println(arr[i])
}
}
To modify the original array, you can pass a pointer to the array:
func modifyArray(arr *[5]int) {
arr[0] = 100
}
Frequently Asked Questions
Q1: How can I find the length of an array in Go?
You can use the built-in len()
function to find the length of an array.
Example:
package main
import "fmt"
func main() {
arr := [5]int{1, 2, 3, 4, 5}
fmt.Println("Length of the array:", len(arr)) // Output: 5
}
Q2: How do I copy an array in Go?
In Go, you can copy an array by simply assigning it to another array of the same type and size.
Example:
package main
import "fmt"
func main() {
original := [3]int{1, 2, 3}
copy := original
fmt.Println("Original:", original) // Output: [1 2 3]
fmt.Println("Copy:", copy) // Output: [1 2 3]
}
Q3: How can I pass an array to a function without copying it?
To avoid copying, you can pass a pointer to the array.
Example:
package main
import "fmt"
func modifyArray(arr *[3]int) {
arr[0] = 42
}
func main() {
arr := [3]int{1, 2, 3}
modifyArray(&arr)
fmt.Println("Modified array:", arr) // Output: [42 2 3]
}
Example code to test: main.go
package main
import "fmt"
func main() {
arr1 := [5]int{1, 2, 3, 4, 5}
arr2 := [5]int{1, 2, 3, 4, 5}
fmt.Println(arr1)
fmt.Println(arr2)
var arr3 [5]int
// fmt.Println(arr3) // this should print [0 0 0 0 0]
// println("Length:", len(arr3))
for i := 0; i < len(arr3); i++ {
fmt.Scan(&arr3[i])
}
fmt.Println(arr3)
strArr := [3]string{"one", "two", "three"}
for i := 0; i < len(strArr); i++ {
fmt.Print(strArr[i]+ "")
}
}
[Author: @mdimamhosen Date: 2025-04-19 Category: interview-qa/boolean Tags: [go, boolean, data-types] ]
A boolean data-type can either be "TRUE" or "FALSE"
package main
import "fmt"
func main() {
isGolangPL := true
isHtmlPL := false
fmt.Println(isGolangPL)
fmt.Println(isHtmlPL)
}
Frequently Asked Questions
Q1: How can I use boolean values in conditional statements?
Answer: Boolean values are often used in conditional statements to control the flow of a program. For example:
package main
import "fmt"
func main() {
isEven := true
if isEven {
fmt.Println("The number is even.")
} else {
fmt.Println("The number is odd.")
}
}
Q2: Can boolean values be compared directly?
Answer: Yes, boolean values can be compared directly using comparison operators. For example:
package main
import "fmt"
func main() {
isTrue := true
isFalse := false
fmt.Println(isTrue == isFalse) // Output: false
fmt.Println(isTrue != isFalse) // Output: true
}
Callback Functions
If a function is passed as an argument to another function, then such types of functions are known as a Higher-Order function. This passing function as an argument is also known as a callback function or first-class function in the Go language.
package main
import "fmt"
func addName(name string, callback func(string)) {
callback(name)
}
func main() {
addName("HuXn", func(nm string) {
fmt.Printf("Hi, my name is %v\n", nm)
})
}
[Author: @mdimamhosen Date: 2025-04-22 Category: interview-qa/arrays Tags: [go, clousers, functions] ]
🔁 Program Code Example
package main
import "fmt"
const a = 10
var b = 20
func Outer() func() {
// Outer function variables
money := 100
age := 20
fmt.Println("Outer function")
fmt.Println("Age:", age)
show := func() {
money += a + b
fmt.Println("Money:", money)
}
return show
}
func call() {
inc := Outer()
inc()
inc()
fmt.Println("=========================")
inc1 := Outer()
inc1()
inc1()
}
func main() {
call()
}
func init() {
fmt.Print("============ Begin ============\n")
}
⚙️ Code Execution Phases
🧩 Phase 1: Compilation
- Compile and generate the binary:
go build main.go
🚀 Phase 2: Execution
- Run the binary:
./main
🔒 Closures in Go
✅ What is a Closure?
A closure is a function defined within another function and has access to the outer function's variables even after the outer function has finished executing.
func Outer() func() {
money := 100
show := func() {
money += 10
fmt.Println("Money:", money)
}
return show
}
money
is captured by the inner function.- On each call to the returned function,
money
is updated.
✅ Multiple Closures
- Each call to
Outer()
creates a new instance ofmoney
, isolated from others.
🧠 Output Explanation
init() runs first: ============ Begin ============
Outer function
Age: 20
Money: 130
Money: 160
=========================
Outer function
Age: 20
Money: 130
Money: 160
- Two closures are created, each with its own instance of
money
. - They do not interfere with each other.
🔍 Types of Closures
1. Closure with Outer Variable
Question: Write a Go program that demonstrates how a closure can access and modify a variable from the outer function.
Code:
package main
import "fmt"
func outer() func() {
x := 10
return func() {
x++
fmt.Println(x)
}
}
func main() {
closure := outer()
closure() // Output: 11
closure() // Output: 12
}
Explanation:
- The
outer
function creates a closure that captures and modifies thex
variable. - Every time the closure is called, the value of
x
is incremented.
2. Multiple Closures with Separate States
Question: Demonstrate how multiple closures created in the same function each maintain their own state.
Code:
package main
import "fmt"
func createCounter() func() int {
counter := 0
return func() int {
counter++
return counter
}
}
func main() {
counter1 := createCounter()
counter2 := createCounter()
fmt.Println(counter1()) // Output: 1
fmt.Println(counter1()) // Output: 2
fmt.Println(counter2()) // Output: 1
fmt.Println(counter2()) // Output: 2
}
Explanation:
counter1
andcounter2
each maintain their own state because they are independent closures.- Each counter starts at 0 and increments on each call.
3. Closure with Parameters
Question: Write a closure that accepts parameters and demonstrates how closures can be passed arguments.
Code:
package main
import "fmt"
func multiplier(factor int) func(int) int {
return func(n int) int {
return n * factor
}
}
func main() {
double := multiplier(2)
triple := multiplier(3)
fmt.Println(double(5)) // Output: 10
fmt.Println(triple(5)) // Output: 15
}
Explanation:
- The closure
multiplier
takes afactor
argument and returns a function that multiplies a number by that factor. - Each closure (
double
,triple
) uses its ownfactor
value to perform the operation.
4. Closures with Deferred Execution
Question: How can closures be used in Go with deferred execution, and what happens when the closure accesses variables after the outer function returns?
Code:
package main
import "fmt"
func main() {
a := 10
defer func(a int) { // Pass 'a' as a parameter to the deferred function
fmt.Println("Deferred closure:", a)
}(a) // Pass the current value of 'a' here
a = 20
fmt.Println("Inside main:", a)
}
Explanation:
- Even though
a
is modified insidemain
, the deferred closure captures the value ofa
at the time the defer statement was encountered by passing it as a parameter. - The closure prints the value of
a
that was captured before it was modified.
5. Closure Capturing Loop Variable
Question: Write a Go program that demonstrates a common pitfall when using closures inside loops. The closure captures the loop variable incorrectly.
Code:
package main
import "fmt"
func main() {
funcs := []func(){}
for i := 0; i < 3; i++ {
funcs = append(funcs, func() {
fmt.Println(i) // Output: 3, 3, 3
})
}
for _, f := range funcs {
f()
}
}
Explanation:
- All closures capture the same
i
variable. At the time of closure execution,i
is 3 (the value after the loop ends). - To fix this, you need to pass
i
as a parameter to the closure:
Fixed Code:
package main
import "fmt"
func main() {
funcs := []func(){}
for i := 0; i < 3; i++ {
i := i // Create a new variable inside the loop
funcs = append(funcs, func() {
fmt.Println(i) // Output: 0, 1, 2
})
}
for _, f := range funcs {
f()
}
}
6. Closures with Function Arguments
Question: Create a closure that adds two numbers and demonstrates how closures can capture arguments passed to the inner function.
Code:
package main
import "fmt"
func adder(a int) func(int) int {
return func(b int) int {
return a + b
}
}
func main() {
add5 := adder(5)
fmt.Println(add5(3)) // Output: 8
fmt.Println(add5(10)) // Output: 15
}
Explanation:
- The outer function
adder
capturesa
and returns a closure that addsa
to the argumentb
. - The closure
add5
remembersa = 5
and adds it to the argument passed to it.
7. Closures with a Function Factory
Question: Implement a closure that acts as a function factory, returning different mathematical operations based on the argument passed to the factory.
Code:
package main
import "fmt"
func operationFactory(operator string) func(int, int) int {
switch operator {
case "add":
return func(a, b int) int {
return a + b
}
case "subtract":
return func(a, b int) int {
return a - b
}
case "multiply":
return func(a, b int) int {
return a * b
}
}
return nil
}
func main() {
add := operationFactory("add")
subtract := operationFactory("subtract")
multiply := operationFactory("multiply")
fmt.Println(add(3, 4)) // Output: 7
fmt.Println(subtract(9, 4)) // Output: 5
fmt.Println(multiply(3, 4)) // Output: 12
}
Explanation:
- The
operationFactory
returns different closures based on the operator passed. - Each closure performs a corresponding mathematical operation.
8. Closures with State Preservation
Question: Write a closure that preserves state across multiple invocations (like a simple counter) and explain its working.
Code:
package main
import "fmt"
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
func main() {
c1 := counter()
c2 := counter()
fmt.Println(c1()) // Output: 1
fmt.Println(c1()) // Output: 2
fmt.Println(c2()) // Output: 1
}
Explanation:
- Each call to
counter
returns a closure that maintains a uniquecount
variable, preserving state across invocations.
9. Closure with Function Composition
Question: Create a Go program that demonstrates function composition using closures.
Code:
package main
import "fmt"
func compose(f, g func(int) int) func(int) int {
return func(x int) int {
return f(g(x))
}
}
func double(x int) int {
return x * 2
}
func addFive(x int) int {
return x + 5
}
func main() {
composed := compose(double, addFive)
fmt.Println(composed(3)) // Output: 16 (3 + 5 = 8, 8 * 2 = 16)
}
Explanation:
- The
compose
function takes two functions (f
andg
) and returns a new function that appliesg
first, then appliesf
to the result. - The result is a composition of
double
andaddFive
.
# Go Closures - 20 Questions with Code Examples and Explanations
This document contains 20 questions related to closures in Go, along with code examples and detailed explanations.
---
### 1. **What is a closure in Go?**
**Question:** Define what a closure is in Go with an example.
**Code:**
```go
package main
import "fmt"
func outer() func() {
return func() {
fmt.Println("This is a closure")
}
}
func main() {
closure := outer()
closure()
}
```
Explanation:
A closure is a function that captures the variables from its surrounding context. In the example, the inner function returned by outer
is a closure, as it can access the environment in which it was created.
2. How does a closure access variables from its outer function?
Question: Show how a closure can access and modify variables in the outer function.
Code:
package main
import "fmt"
func outer() func() {
x := 10
return func() {
x++
fmt.Println(x)
}
}
func main() {
closure := outer()
closure() // Output: 11
closure() // Output: 12
}
Explanation:
The closure captures the x
variable from the outer
function and modifies it each time it is invoked.
3. What happens when closures access variables from a loop?
Question: Demonstrate the common mistake with closures capturing loop variables.
Code:
package main
import "fmt"
func main() {
funcs := []func(){}
for i := 0; i < 3; i++ {
funcs = append(funcs, func() {
fmt.Println(i)
})
}
for _, f := range funcs {
f()
}
}
Explanation:
All closures capture the same i
variable, and when executed, they all print 3
. This happens because the closure captures a reference to the variable i
, not its value at the time of closure creation.
4. How can you fix the loop closure problem?
Question: How can you avoid closures capturing the same variable in a loop?
Code:
package main
import "fmt"
func main() {
funcs := []func(){}
for i := 0; i < 3; i++ {
i := i // New variable for each iteration
funcs = append(funcs, func() {
fmt.Println(i)
})
}
for _, f := range funcs {
f()
}
}
Explanation:
By introducing a new variable i
in the loop, each closure captures a separate value of i
, resulting in 0
, 1
, and 2
being printed.
5. Closures as Function Parameters
Question: How do you pass a closure as an argument to another function?
Code:
package main
import "fmt"
func applyClosure(f func()) {
f()
}
func main() {
closure := func() {
fmt.Println("Closure passed as argument")
}
applyClosure(closure)
}
Explanation:
You can pass a closure as an argument to another function. In this example, applyClosure
accepts a closure and invokes it.
6. Closures with Parameters
Question: Write a closure that accepts a parameter and demonstrates how closures work with arguments.
Code:
package main
import "fmt"
func multiplier(factor int) func(int) int {
return func(n int) int {
return n * factor
}
}
func main() {
double := multiplier(2)
fmt.Println(double(4)) // Output: 8
}
Explanation:
The closure multiplier
takes a parameter factor
and returns a function that multiplies the given number n
by factor
.
7. Closures with Function Return Values
Question: How do closures work when they return values?
Code:
package main
import "fmt"
func adder(a int) func(int) int {
return func(b int) int {
return a + b
}
}
func main() {
addFive := adder(5)
fmt.Println(addFive(3)) // Output: 8
}
Explanation:
The closure captures the a
variable and uses it when adding b
in the returned function.
8. Returning a Closure from a Function
Question: Demonstrate how to return a closure from a function.
Code:
package main
import "fmt"
func createCounter() func() int {
counter := 0
return func() int {
counter++
return counter
}
}
func main() {
counter1 := createCounter()
counter2 := createCounter()
fmt.Println(counter1()) // Output: 1
fmt.Println(counter2()) // Output: 1
}
Explanation:
Each call to createCounter
creates a new closure, which maintains its own counter state.
9. Closure with State Preservation
Question: Write a closure that remembers its previous state across calls.
Code:
package main
import "fmt"
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
func main() {
c1 := counter()
c2 := counter()
fmt.Println(c1()) // Output: 1
fmt.Println(c1()) // Output: 2
fmt.Println(c2()) // Output: 1
}
Explanation:
A closure retains its own state, meaning each call to counter
results in separate states for c1
and c2
.
10. Closures and Anonymous Functions
Question: How can closures be used with anonymous functions?
Code:
package main
import "fmt"
func main() {
a := 5
closure := func() {
fmt.Println("Captured value:", a)
}
closure() // Output: Captured value: 5
}
Explanation:
Anonymous functions can be used as closures. In this case, the anonymous function captures the variable a
.
[Author: @mdimamhosen Date: 2025-04-19 Category: e.g., interview-qa/topic_name Tags: [go, concurrency, channels] ]
Comparison Operators
Comparison operators are used to compare two values
Operator | Name | Example |
---|---|---|
== | Equal to | x == y |
!= | Not equal | x != y |
> | Greater than | x > y |
< | Less than | x < y |
>= | Greater than or equal to | x >= y |
<= | Less than or equal to | x <= y |
package main
import "fmt"
func main() {
fmt.Println(2 > 2) // false
fmt.Println(2 < 2) // false
fmt.Println(2 >= 2) // true
fmt.Println(2 <= 2) // true
fmt.Println(2 == 2) // true
fmt.Println(2 != 2) // false
}
Frequently Asked Questions
1. What is the purpose of comparison operators in Go?
Answer: Comparison operators are used to compare two values and return a boolean result (true or false).
Example:
package main
import "fmt"
func main() {
x := 10
y := 20
fmt.Println(x > y) // false
fmt.Println(x < y) // true
}
2. Can comparison operators be used with strings in Go?
Answer: Yes, comparison operators can be used with strings to compare their lexicographical order.
Example:
package main
import "fmt"
func main() {
fmt.Println("apple" > "banana") // false
fmt.Println("apple" < "banana") // true
}
3. How does the ==
operator work with structs in Go?
Answer: The ==
operator can be used to compare structs if all their fields are comparable.
Example:
package main
import "fmt"
type Point struct {
x, y int
}
func main() {
p1 := Point{1, 2}
p2 := Point{1, 2}
fmt.Println(p1 == p2) // true
}
4. What happens if you compare two different types in Go?
Answer: Comparing two different types will result in a compile-time error.
Example:
package main
func main() {
// Uncommenting the following line will cause a compile-time error
// fmt.Println(10 == "10")
}
5. Can comparison operators be used with pointers?
Answer: Yes, comparison operators can be used to compare pointers for equality or inequality.
Example:
package main
import "fmt"
func main() {
a := 10
b := 10
pa := &a
pb := &b
fmt.Println(pa == pb) // false
}
6. How does the !=
operator work?
Answer: The !=
operator checks if two values are not equal.
Example:
package main
import "fmt"
func main() {
x := 5
y := 10
fmt.Println(x != y) // true
}
7. Can comparison operators be used with arrays?
Answer: Yes, arrays can be compared using ==
and !=
if their elements are comparable.
Example:
package main
import "fmt"
func main() {
a1 := [3]int{1, 2, 3}
a2 := [3]int{1, 2, 3}
fmt.Println(a1 == a2) // true
}
8. What is the result of comparing two slices using ==
?
Answer: Slices cannot be compared using ==
except for comparison with nil
.
Example:
package main
import "fmt"
func main() {
s1 := []int{1, 2, 3}
s2 := []int{1, 2, 3}
fmt.Println(s1 == nil) // false
// Uncommenting the following line will cause a compile-time error
// fmt.Println(s1 == s2)
}
9. How does Go handle floating-point comparison?
Answer: Floating-point numbers can be compared using comparison operators, but be cautious of precision issues.
Example:
package main
import "fmt"
func main() {
x := 0.1 + 0.2
y := 0.3
fmt.Println(x == y) // false due to precision issues
}
10. Can you compare custom types using comparison operators?
Answer: Custom types can be compared if their underlying types support comparison.
Example:
package main
import "fmt"
type Age int
func main() {
var a1 Age = 30
var a2 Age = 25
fmt.Println(a1 > a2) // true
}
[Author: @mdimamhosen Date: 2025-04-19 Category: interview-qa/conditional-statements Tags: [go, conditional-statements, if-else] ]
Go Conditions
Conditional statements allow us to control the structure of our program.
There are different ways by which we can control the flow of our program, (If, else if, else) are one of them.
(If, else if, else) statments allow us to make "decisions" while our program is running, They're also called (conditional statments) in programming.
// Sudo Syntax
if condition { <code> }
else if condition { <code> }
else { <code> }
// Actual Code
package main
import "fmt"
func main() {
password := "12345678"
if len(password) > 7 {
fmt.Println("Valid Password")
} else {
fmt.Println("Invalid Password")
}
}
Frequently Asked Questions (FAQs)
1. What is the syntax of an if-else statement in Go?
Answer: The syntax of an if-else statement in Go is as follows:
if condition {
// code to execute if condition is true
} else {
// code to execute if condition is false
}
Example:
package main
import "fmt"
func main() {
number := 10
if number%2 == 0 {
fmt.Println("Even Number")
} else {
fmt.Println("Odd Number")
}
}
2. Can we use an if statement without an else block?
Answer: Yes, an if statement can be used without an else block. Example:
package main
import "fmt"
func main() {
number := 5
if number > 0 {
fmt.Println("Positive Number")
}
}
3. What is an else-if ladder in Go?
Answer: An else-if ladder is used to check multiple conditions sequentially. Example:
package main
import "fmt"
func main() {
score := 85
if score >= 90 {
fmt.Println("Grade: A")
} else if score >= 75 {
fmt.Println("Grade: B")
} else {
fmt.Println("Grade: C")
}
}
4. How do you use a short statement in an if condition?
Answer: A short statement can be used to initialize a variable within an if condition. Example:
package main
import "fmt"
func main() {
if num := 10; num%2 == 0 {
fmt.Println("Even Number")
}
}
5. Can we nest if-else statements in Go?
Answer: Yes, if-else statements can be nested. Example:
package main
import "fmt"
func main() {
number := 15
if number > 0 {
if number%2 == 0 {
fmt.Println("Positive Even Number")
} else {
fmt.Println("Positive Odd Number")
}
} else {
fmt.Println("Non-Positive Number")
}
}
6. What is the difference between if-else and switch statements?
Answer: If-else is used for conditional branching, while switch is used for selecting one of many blocks of code. Example:
package main
import "fmt"
func main() {
day := 3
switch day {
case 1:
fmt.Println("Monday")
case 2:
fmt.Println("Tuesday")
case 3:
fmt.Println("Wednesday")
default:
fmt.Println("Invalid Day")
}
}
7. How do you handle multiple conditions in a single if statement?
Answer:
Logical operators like &&
(AND) and ||
(OR) can be used to handle multiple conditions.
Example:
package main
import "fmt"
func main() {
number := 15
if number > 0 && number%3 == 0 {
fmt.Println("Positive and Divisible by 3")
}
}
8. What happens if the condition in an if statement is not a boolean?
Answer: In Go, the condition in an if statement must evaluate to a boolean. Otherwise, it will result in a compilation error. Example:
// This will cause a compilation error
// if 10 {
// fmt.Println("Invalid Condition")
// }
9. Can we use a function call in an if condition?
Answer: Yes, a function call can be used in an if condition. Example:
package main
import "fmt"
func isEven(num int) bool {
return num%2 == 0
}
func main() {
if isEven(10) {
fmt.Println("Even Number")
}
}
10. How do you use if-else with user input?
Answer:
You can use the fmt.Scan
function to take user input and use it in an if-else statement.
Example:
package main
import "fmt"
func main() {
var age int
fmt.Print("Enter your age: ")
fmt.Scan(&age)
if age >= 18 {
fmt.Println("You are eligible to vote.")
} else {
fmt.Println("You are not eligible to vote.")
}
}
[Author: @mdimamhosen Date: 2025-04-19 Category: interview-qa/constants Tags: [go, constants, beginner] ]
The const keyword declares the variable as "constant", which means that it is unchangeable and read-only.
package main
import ("fmt")
const user = "admin" // cannot be changed
func main() {
fmt.Println("admin")
}
Constant Rules
1. Constant names follow the same naming rules as variables
2. Constant names are usually written in uppercase letters
3. Constants can be declared both inside and outside of a function
Frequently Asked Questions
1. What is a constant in Go?
Answer: A constant is a variable whose value cannot be changed once it is assigned. Constants are declared using the const
keyword.
Code Example:
package main
import "fmt"
const PI = 3.14
func main() {
fmt.Println("The value of PI is:", PI)
}
2. Can constants be declared inside a function?
Answer: Yes, constants can be declared both inside and outside of a function.
Code Example:
package main
import "fmt"
func main() {
const GREETING = "Hello, World!"
fmt.Println(GREETING)
}
3. Can constants hold values other than numbers?
Answer: Yes, constants can hold string, boolean, or even character values.
Code Example:
package main
import "fmt"
const IS_ACTIVE = true
const MESSAGE = "Welcome to Go!"
func main() {
fmt.Println("Is Active:", IS_ACTIVE)
fmt.Println("Message:", MESSAGE)
}
4. Can constants be computed at runtime?
Answer: No, constants must be assigned a value that can be determined at compile time.
Code Example:
package main
import "fmt"
const VALUE = 10 * 2 // Valid
func main() {
fmt.Println("Value:", VALUE)
}
5. What happens if you try to change a constant's value?
Answer: The compiler will throw an error if you try to change the value of a constant.
Code Example:
package main
import "fmt"
const NAME = "John"
func main() {
// NAME = "Doe" // Uncommenting this line will cause a compilation error
fmt.Println(NAME)
}
6. Can constants be used in expressions?
Answer: Yes, constants can be used in expressions to compute other constants.
Code Example:
package main
import "fmt"
const A = 5
const B = 10
const SUM = A + B
func main() {
fmt.Println("Sum:", SUM)
}
7. What is the difference between const
and var
in Go?
Answer: const
is used for values that do not change, while var
is used for variables whose values can change.
Code Example:
package main
import "fmt"
const FIXED = 100
var changeable = 200
func main() {
fmt.Println("Fixed:", FIXED)
fmt.Println("Changeable:", changeable)
changeable = 300
fmt.Println("Updated Changeable:", changeable)
}
8. Can constants be of type array or slice?
Answer: No, constants cannot be of type array, slice, or map.
Code Example:
package main
import "fmt"
func main() {
// const ARR = [3]int{1, 2, 3} // This will cause a compilation error
fmt.Println("Constants cannot be arrays or slices.")
}
9. Can constants be exported in Go?
Answer: Yes, constants can be exported if their names start with an uppercase letter.
Code Example:
package main
import "fmt"
const ExportedConstant = "I am exported!"
func main() {
fmt.Println(ExportedConstant)
}
10. What are untyped constants in Go?
Answer: Untyped constants do not have a specific type until they are assigned to a variable.
Code Example:
package main
import "fmt"
const VALUE = 42
func main() {
var x int = VALUE
var y float64 = VALUE
fmt.Println("x:", x, "y:", y)
}
Defer Keyword
The defer
keyword is used to delay the execution of a function or a statement until the nearby function returns. In simple words, defer
will move the execution of the statement to the very end inside a function.
package main
import "fmt"
func greet() {
defer fmt.Println("World")
fmt.Println("Hello")
}
func main() {
greet()
}
[Author: @fardinabir Date: 2025-04-27 Category: interview-qa/go-routines Tags: [go, go-routines, concurrency, routine]
Top 15 Golang Interview Questions on Concurrency and Goroutines (Detailed Answers with Bonus)
This page provides a comprehensive list of 15 Go interview questions focused on concurrency and goroutines, with detailed, explanatory answers, followed by a bonus question comparing Go’s concurrency model to other languages. The questions cover theoretical concepts, practical applications, and common pitfalls, suitable for interview preparation or deepening your understanding of Go’s concurrency model. The bonus question explores why Go’s goroutines are praised compared to concurrency mechanisms in Java, Python, and other languages, with a focus on efficiency and performance.

1. What are goroutines, and how do they differ from threads?
Answer:
Goroutines are lightweight, user-space threads managed by the Go runtime rather than the operating system. They enable concurrent execution of functions with minimal overhead, making it practical to create thousands or even millions of goroutines in a single program.
Key Differences from Threads:
- Management: Goroutines are managed by the Go runtime’s scheduler, while threads are managed by the OS. This allows Go to optimize goroutine scheduling without relying on OS-level thread switching, which is costly.
- Memory Overhead: Goroutines start with a small stack (as low as 2KB, dynamically growing as needed), whereas OS threads typically require a fixed, larger stack (e.g., 1MB on Linux). This makes goroutines far more memory-efficient.
- Creation and Switching: Creating and context-switching goroutines is faster because it happens in user space, avoiding system calls. Thread creation and switching involve OS kernel operations, which are slower.
- Scalability: Go’s scheduler multiplexes many goroutines onto a smaller number of OS threads, enabling efficient scaling. Threads are limited by OS constraints and resource availability.
- Concurrency Model: Goroutines follow Go’s concurrency model, emphasizing channels for communication, while threads often rely on locks and shared memory, which can lead to complex synchronization issues.
Example:
package main
import (
"fmt"
"time"
)
func printNumbers() {
for i := 1; i <= 5; i++ {
fmt.Println(i)
time.Sleep(100 * time.Millisecond)
}
}
func main() {
go printNumbers() // Runs concurrently
printNumbers() // Runs in main goroutine
time.Sleep(1 * time.Second) // Wait for goroutines to finish
}
In this example, go printNumbers()
spawns a new goroutine, allowing two functions to run concurrently. Unlike threads, creating this goroutine is inexpensive and managed entirely by Go.
2. How does the Go scheduler work with goroutines?
Answer:
The Go scheduler is part of the Go runtime and is responsible for managing the execution of goroutines. It uses a model called the M:N scheduler, where M goroutines are multiplexed onto N OS threads. The scheduler ensures efficient utilization of CPU resources and minimizes overhead.
Key Components:
- G (Goroutine): Represents a single goroutine, including its stack, program counter, and state.
- M (Machine): Represents an OS thread, which executes goroutines.
- P (Processor): A logical processor that schedules goroutines onto an M. The number of Ps is set by
GOMAXPROCS
(defaults to the number of CPU cores).
How It Works:
- Goroutine Creation: When a goroutine is created (via
go
keyword), it’s added to a run queue managed by a P. - Scheduling: Each P has a local run queue of goroutines. The scheduler assigns Ps to Ms (OS threads), and Ps execute goroutines from their queues.
- Work Stealing: If a P’s run queue is empty, it can steal goroutines from another P’s queue, balancing the workload.
- Preemption: The scheduler can preempt long-running goroutines (e.g., during function calls or blocking operations like syscalls) to ensure fairness.
- Blocking Handling: If a goroutine performs a blocking operation (e.g., I/O), the scheduler parks it and assigns another goroutine to the thread, maximizing CPU usage.
Example:
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Println("GOMAXPROCS:", runtime.GOMAXPROCS(0)) // Number of Ps
for i := 0; i < 10; i++ {
go func(id int) {
for {
fmt.Printf("Goroutine %d running\n", id)
}
}(i)
}
select {} // Keep main goroutine alive
}
Here, multiple goroutines are scheduled across available Ps. The scheduler ensures they share CPU time, and GOMAXPROCS
determines how many threads can run goroutines simultaneously.
3. What is the purpose of the go
keyword in Go?
Answer:
The go
keyword is used to launch a new goroutine, enabling a function to execute concurrently with other goroutines, including the main program. It’s a simple, idiomatic way to introduce concurrency in Go without explicitly managing threads.
Purpose:
- Concurrency: Allows functions to run independently, improving performance for tasks like parallel processing, I/O-bound operations, or background tasks.
- Simplicity: Abstracts away low-level thread management, letting the Go runtime handle scheduling.
- Scalability: Enables creating many goroutines (e.g., for handling thousands of connections) due to their low overhead.
How It Works:
When go function()
is called, the Go runtime creates a new goroutine, places it in a run queue, and schedules it for execution. The calling goroutine continues immediately, without waiting for the new goroutine to complete.
Example:
package main
import (
"fmt"
"time"
)
func sayHello() {
fmt.Println("Hello from goroutine!")
}
func main() {
go sayHello() // Launch goroutine
fmt.Println("Hello from main!")
time.Sleep(100 * time.Millisecond) // Allow goroutine to run
}
In this example, go sayHello()
runs sayHello
concurrently. Without time.Sleep
, the main goroutine might exit before sayHello
prints, as goroutines are not guaranteed to execute immediately.
Note: The time.Sleep
is used here for demonstration. In production, use synchronization mechanisms like sync.WaitGroup
or channels to coordinate goroutines.
4. How do you synchronize goroutines in Go?
Answer:
Synchronization in Go ensures that goroutines coordinate their actions, avoiding issues like race conditions or accessing shared resources incorrectly. Go provides two primary approaches: channels for communication-based synchronization and sync package primitives for traditional locking.
Approaches:
-
Channels:
- Channels are the idiomatic way to synchronize goroutines, following Go’s philosophy: “Don’t communicate by sharing memory; share memory by communicating.”
- Channels allow goroutines to send and receive data, inherently synchronizing their execution.
- Example:
Here, the main goroutine waits for the message, ensuring synchronization.package main import "fmt" func main() { ch := make(chan string) go func() { ch <- "Hello from goroutine!" // Send }() msg := <-ch // Receive, blocks until data is sent fmt.Println(msg) }
-
sync.WaitGroup:
- Used to wait for multiple goroutines to complete.
- Methods:
Add(n)
to set the number of goroutines,Done()
to signal completion, andWait()
to block until all are done. - Example:
package main import ( "fmt" "sync" ) func worker(id int, wg *sync.WaitGroup) { defer wg.Done() fmt.Printf("Worker %d done\n", id) } func main() { var wg sync.WaitGroup for i := 1; i <= 3; i++ { wg.Add(1) go worker(i, &wg) } wg.Wait() fmt.Println("All workers done") }
-
sync.Mutex and sync.RWMutex:
sync.Mutex
provides mutual exclusion, ensuring only one goroutine accesses a critical section at a time.sync.RWMutex
allows multiple readers or one writer, useful for read-heavy workloads.- Example:
package main import ( "fmt" "sync" ) var counter int var mu sync.Mutex func increment(wg *sync.WaitGroup) { defer wg.Done() mu.Lock() counter++ mu.Unlock() } func main() { var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) go increment(&wg) } wg.Wait() fmt.Println("Counter:", counter) // Always 100 }
Best Practice: Prefer channels for coordination and data passing, as they reduce the risk of errors like deadlocks or race conditions compared to mutexes.
5. What are channels, and how do they facilitate concurrency?
Answer:
Channels are typed, thread-safe conduits that allow goroutines to communicate by sending and receiving values. They are a core feature of Go’s concurrency model, enabling safe and idiomatic coordination without shared memory.
Key Characteristics:
- Typed: Channels carry values of a specific type (e.g.,
chan int
,chan string
). - Synchronized: Sending and receiving operations block until both sender and receiver are ready (for unbuffered channels), ensuring coordination.
- Safe: Channels prevent race conditions by serializing access to data.
Types of Channels:
- Unbuffered: Created with
make(chan T)
. Sending blocks until a receiver is ready, and receiving blocks until a sender is ready. - Buffered: Created with
make(chan T, n)
. Allows sending up ton
values without blocking, but blocks when the buffer is full or empty.
How Channels Facilitate Concurrency:
- Communication: Channels allow goroutines to pass data, coordinating their execution. For example, a producer goroutine can send data to a consumer goroutine.
- Synchronization: Blocking behavior ensures goroutines wait for each other, preventing premature execution.
- Control Flow: Channels can signal events, like completion or cancellation, using empty structs (
chan struct{}
).
Example:
package main
import (
"fmt"
"time"
)
func producer(ch chan<- int) {
for i := 1; i <= 5; i++ {
ch <- i
time.Sleep(100 * time.Millisecond)
}
close(ch)
}
func main() {
ch := make(chan int)
go producer(ch)
for v := range ch {
fmt.Println("Received:", v)
}
}
Here, the producer sends integers, and the main goroutine receives them. The range
loop exits when the channel is closed, demonstrating clean coordination.
Use Cases:
- Pipelines for data processing.
- Worker pools for task distribution.
- Signaling completion or cancellation.
6. What is the difference between buffered and unbuffered channels?
Answer:
Channels in Go can be unbuffered or buffered, and their behavior differs significantly in terms of blocking and synchronization.
Unbuffered Channels:
- Created with
make(chan T)
. - Behavior: Sending (
ch <- v
) blocks until a receiver is ready (<-ch
), and receiving blocks until a sender is ready. This ensures strict synchronization. - Use Case: Ideal for scenarios requiring guaranteed handoff, like coordinating two goroutines.
- Example:
package main import "fmt" func main() { ch := make(chan string) go func() { ch <- "Hello" // Blocks until main receives }() fmt.Println(<-ch) // Blocks until goroutine sends }
Buffered Channels:
- Created with
make(chan T, n)
, wheren
is the buffer size. - Behavior: Sending blocks only if the buffer is full, and receiving blocks only if the buffer is empty. This allows asynchronous communication within the buffer’s capacity.
- Use Case: Useful for decoupling producers and consumers or handling bursts of data.
- Example:
package main import "fmt" func main() { ch := make(chan int, 2) ch <- 1 // Non-blocking ch <- 2 // Non-blocking // ch <- 3 // Would block (buffer full) fmt.Println(<-ch) // 1 fmt.Println(<-ch) // 2 }
Key Differences:
- Synchronization: Unbuffered channels enforce strict synchronization; buffered channels allow some asynchrony.
- Blocking: Unbuffered channels always block unless both sender and receiver are ready; buffered channels block only when the buffer is full or empty.
- Use Cases: Unbuffered for tight coordination; buffered for throughput or decoupling.
Pitfall: Overusing buffered channels can hide synchronization issues or lead to goroutine leaks if the buffer fills and no receiver consumes the data.
7. How does select
work with channels?
Answer:
The select
statement in Go allows a goroutine to wait on multiple channel operations (send or receive) simultaneously, proceeding with the first operation that becomes ready. It’s analogous to a switch
for channels, enabling flexible concurrency patterns.
Key Features:
- Non-blocking Choice: If multiple channel operations are ready,
select
randomly chooses one. - Default Case: An optional
default
case runs if no channel operation is ready, makingselect
non-blocking. - Blocking: Without a
default
case,select
blocks until at least one channel operation is ready.
Syntax:
select {
case v := <-ch1:
// Handle value from ch1
case ch2 <- x:
// Handle sending x to ch2
case v, ok := <-ch3:
// Handle value or channel closure
default:
// Run if no channel is ready
}
Example:
package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
time.Sleep(1 * time.Second)
ch1 <- "from ch1"
}()
go func() {
time.Sleep(2 * time.Second)
ch2 <- "from ch2"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-ch1:
fmt.Println("Received:", msg1)
case msg2 := <-ch2:
fmt.Println("Received:", msg2)
}
}
}
How It Works:
- The
select
waits for eitherch1
orch2
to send a value. - After 1 second,
ch1
sends, andselect
processes it. - After another second,
ch2
sends, andselect
processes it.
Use Cases:
- Multiplexing: Handle multiple channels in a single goroutine (e.g., aggregating logs).
- Timeouts: Combine with
time.After
to limit waiting time. - Non-blocking Checks: Use
default
to check channel readiness without blocking.
Example with Timeout:
select {
case msg := <-ch:
fmt.Println("Received:", msg)
case <-time.After(1 * time.Second):
fmt.Println("Timeout")
}
Pitfall: Avoid empty select{}
(causes deadlock) or select
with only default
in a loop (can consume CPU).
8. What is a race condition, and how can you detect and prevent it in Go?
Answer:
A race condition occurs when multiple goroutines access shared data concurrently, and at least one access is a write, leading to unpredictable results. Race conditions are a common concurrency bug, especially in programs with shared memory.
Example of a Race Condition:
package main
import (
"fmt"
"sync"
)
var counter int
func increment() {
counter++ // Read, increment, write (not atomic)
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
increment()
}()
}
wg.Wait()
fmt.Println("Counter:", counter) // Likely not 1000
}
Here, counter++
is not atomic, so concurrent increments may overwrite each other, resulting in a final value less than 1000.
Detecting Race Conditions:
- Use the race detector by running your program with
go run -race
,go test -race
, orgo build -race
. - The race detector instruments memory accesses and reports potential races, even if they don’t cause immediate errors.
- Example: Running the above code with
go run -race
will flag the race oncounter
.
Preventing Race Conditions:
-
Mutexes:
- Use
sync.Mutex
to ensure exclusive access to shared data. - Example:
var mu sync.Mutex func increment() { mu.Lock() counter++ mu.Unlock() }
- Use
-
Channels:
- Use channels to serialize access to data, avoiding shared memory.
- Example:
func main() { ch := make(chan int) go func() { sum := 0 for i := 0; i < 1000; i++ { sum++ } ch <- sum }() fmt.Println("Counter:", <-ch) }
-
Atomic Operations:
- Use
sync/atomic
for simple operations like counters. - Example:
var counter int64 func increment() { atomic.AddInt64(&counter, 1) }
- Use
-
Avoid Shared Memory:
- Design goroutines to communicate via channels, reducing the need for locks.
Best Practice: Run tests with -race
in CI pipelines to catch race conditions early.
9. What is the purpose of sync.WaitGroup
?
Answer:
The sync.WaitGroup
is a synchronization primitive in the sync
package used to wait for a collection of goroutines to complete their execution. It’s particularly useful when you need to ensure that all concurrent tasks finish before proceeding.
How It Works:
- Add(n): Increments the WaitGroup counter by
n
, representing the number of goroutines to wait for. - Done(): Decrements the counter by 1, typically called when a goroutine completes.
- Wait(): Blocks until the counter reaches 0, indicating all goroutines have called
Done()
.
Example:
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Second)
fmt.Printf("Worker %d done\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait()
fmt.Println("All workers completed")
}
Key Points:
- Thread-Safe:
sync.WaitGroup
is safe for concurrent use. - Reusable: A WaitGroup can be reused after
Wait()
returns, but you must callAdd()
again. - Common Pitfall: Calling
Done()
without a correspondingAdd()
or callingAdd()
afterWait()
starts can cause panics or incorrect behavior.
Use Case:
- Waiting for multiple API calls to complete.
- Coordinating parallel tasks in a worker pool.
Alternative: Channels can achieve similar coordination but are better for passing data or signaling specific events.
10. How do you implement a worker pool using goroutines?
Answer:
A worker pool is a pattern where a fixed number of goroutines (workers) process tasks from a shared channel, allowing controlled concurrency and efficient resource usage. It’s commonly used for tasks like processing jobs, handling requests, or performing computations.
Steps to Implement:
- Create a channel for tasks (jobs).
- Launch a fixed number of worker goroutines that read from the task channel.
- Send tasks to the channel.
- Collect results (if needed) via another channel.
- Close the task channel to signal workers to exit.
Example:
package main
import (
"fmt"
"sync"
)
func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
for j := range jobs {
fmt.Printf("Worker %d processing job %d\n", id, j)
results <- j * 2 // Process job
}
}
func main() {
const numWorkers = 3
jobs := make(chan int, 100)
results := make(chan int, 100)
var wg sync.WaitGroup
// Start workers
for w := 1; w <= numWorkers; w++ {
wg.Add(1)
go worker(w, jobs, results, &wg)
}
// Send jobs
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs)
// Wait for workers to finish
wg.Wait()
close(results)
// Collect results
for r := range results {
fmt.Println("Result:", r)
}
}
Explanation:
- Jobs Channel:
jobs
is a buffered channel holding tasks (integers in this case). - Workers: Three goroutines read from
jobs
, process tasks (multiply by 2), and send results toresults
. - Results Channel: Collects processed outputs.
- WaitGroup: Ensures all workers finish before closing
results
. - Channel Closure: Closing
jobs
signals workers to exit after processing all tasks.
Benefits:
- Limits concurrency to a fixed number of workers, preventing resource exhaustion.
- Decouples task submission from processing.
- Scales easily by adjusting the number of workers or buffer size.
Use Cases:
- Processing batches of database queries.
- Handling HTTP requests in a server.
- Parallel file processing.
11. What happens if a goroutine panics?
Answer:
A panic in Go is a runtime error that typically causes the program to crash. When a goroutine panics, the behavior depends on whether the panic is recovered.
What Happens:
- If a goroutine panics and the panic is not recovered, the entire program terminates with a stack trace, including the panicking goroutine’s state.
- Other goroutines are not directly affected until the program crashes, but they may not complete their work due to the abrupt termination.
- Panics can occur due to errors like nil pointer dereferences, index out of bounds, or explicit calls to
panic()
.
Recovering Panics:
- Use
defer
withrecover()
to catch and handle panics within a goroutine. recover()
returns the value passed topanic()
if called in a deferred function; otherwise, it returnsnil
.- Example:
package main import "fmt" func safeGoroutine() { defer func() { if r := recover(); r != nil { fmt.Println("Recovered from panic:", r) } }() panic("Something went wrong") } func main() { go safeGoroutine() go func() { panic("Unrecovered panic") // Crashes program }() fmt.Println("Main continues") select {} // Keep program alive }
Key Points:
- Isolation: Each goroutine must handle its own panics; a panic in one goroutine doesn’t directly affect others until the program crashes.
- Best Practice: Always use
defer recover()
in goroutines that might panic to prevent program crashes, especially in long-running servers. - Logging: Log recovered panics for debugging (e.g., to a monitoring system).
- Pitfall: Overusing
recover()
can hide bugs; use it only for specific, recoverable errors.
Use Case: In a web server, recover panics in request-handling goroutines to prevent one bad request from crashing the entire server.
12. How can you limit the number of concurrent goroutines?
Answer:
Limiting concurrent goroutines is essential to control resource usage (e.g., CPU, memory, or network connections) and prevent overwhelming a system. Common techniques include using a semaphore (via a buffered channel) or a worker pool.
Technique 1: Semaphore with Buffered Channel:
- A buffered channel acts as a semaphore, where the buffer size limits the number of concurrent goroutines.
- Sending to the channel “acquires” a slot, and receiving “releases” it.
- Example:
package main import ( "fmt" "sync" "time" ) func task(id int, sem chan struct{}, wg *sync.WaitGroup) { defer wg.Done() defer func() { <-sem }() // Release semaphore fmt.Printf("Task %d running\n", id) time.Sleep(time.Second) } func main() { const maxConcurrency = 2 sem := make(chan struct{}, maxConcurrency) var wg sync.WaitGroup for i := 1; i <= 5; i++ { wg.Add(1) sem <- struct{}{} // Acquire semaphore go task(i, sem, &wg) } wg.Wait() }
Technique 2: Worker Pool:
- As shown in question 10, a worker pool limits concurrency by launching a fixed number of workers.
- Tasks are sent to a channel, and only the available workers process them.
Key Considerations:
- Semaphore Size: Choose a buffer size based on system resources (e.g., CPU cores, database connections).
- Error Handling: Ensure tasks handle errors to avoid deadlocks or leaks.
- Resource Cleanup: Use
defer
to release semaphore slots or close channels properly.
Use Case: Limiting concurrent HTTP requests or database queries to avoid overloading a server.
13. What is the difference between close
and nil
channels?
Answer:
Channels in Go can be in different states, including closed and nil, and their behavior differs significantly in terms of sending, receiving, and usage in select
.
Closed Channel:
- A channel is closed using
close(ch)
. - Behavior:
- Sending to a closed channel causes a panic.
- Receiving from a closed channel returns the zero value of the channel’s type immediately, with
ok
set tofalse
inv, ok := <-ch
. - Closing a channel signals that no more values will be sent, often used to broadcast completion.
- Example:
package main import "fmt" func main() { ch := make(chan int) go func() { ch <- 1 close(ch) }() v, ok := <-ch fmt.Println(v, ok) // 1, true v, ok = <-ch fmt.Println(v, ok) // 0, false // ch <- 2 // Panic: send on closed channel }
Nil Channel:
- A channel is
nil
if it’s declared but not initialized (e.g.,var ch chan int
). - Behavior:
- Sending or receiving on a
nil
channel blocks forever. - In a
select
, anil
channel is effectively ignored, as its operations are never ready.
- Sending or receiving on a
- Example:
package main import "fmt" func main() { var ch chan int select { case v := <-ch: fmt.Println(v) // Never executes default: fmt.Println("Nil channel ignored") } }
Key Differences:
- Purpose: Closing a channel signals completion; a
nil
channel is typically an uninitialized or dynamically disabled channel. - Operations: Closed channels allow receiving (zero values);
nil
channels block all operations. - Select Behavior: A closed channel may trigger a case (if not drained); a
nil
channel is skipped.
Use Cases:
- Closed Channel: Signal task completion or broadcast to multiple receivers.
- Nil Channel: Dynamically enable/disable channel operations in
select
(e.g., toggling a timeout channel).
Pitfall: Closing a channel twice or closing a nil
channel causes a panic.
14. How does context help manage goroutines?
Answer:
The context
package provides a way to manage goroutine lifecycles by carrying deadlines, cancellation signals, and key-value pairs across API boundaries. It’s widely used to coordinate and terminate goroutines gracefully, especially in long-running or networked applications.
Key Features:
- Context Types:
context.Background()
: Root context, used as a starting point.context.TODO()
: Placeholder for contexts not yet defined.context.WithCancel
: Adds cancellation.context.WithTimeout
/WithDeadline
: Adds a time-based cutoff.context.WithValue
: Attaches key-value pairs (use sparingly).
- Methods:
Done()
: Returns a channel that closes when the context is canceled or times out.Err()
: Returns the reason for cancellation (e.g.,context.Canceled
,context.DeadlineExceeded
).Deadline()
: Returns the context’s deadline (if any).Value()
: Retrieves a value by key.
How It Manages Goroutines:
- Cancellation: A context’s
Done()
channel signals goroutines to stop work, allowing graceful shutdown. - Timeouts/Deadlines: Ensures goroutines don’t run indefinitely, critical for timeouts in network requests.
- Propagation: Contexts can be passed through a call chain, coordinating multiple goroutines.
Example:
package main
import (
"context"
"fmt"
"time"
)
func longRunningTask(ctx context.Context, id int) {
select {
case <-time.After(2 * time.Second): // Simulate work
fmt.Printf("Task %d completed\n", id)
case <-ctx.Done():
fmt.Printf("Task %d canceled: %v\n", id, ctx.Err())
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
for i := 1; i <= 3; i++ {
go longRunningTask(ctx, i)
}
time.Sleep(3 * time.Second) // Wait to see results
}
Explanation:
- The context times out after 1 second, closing its
Done()
channel. - Tasks check
ctx.Done()
and exit early if canceled, printing the error.
Best Practices:
- Always pass contexts explicitly (don’t store in structs).
- Cancel contexts using
cancel()
to free resources. - Use
context.WithValue
sparingly, as it can obscure intent. - Check
ctx.Done()
frequently in long-running loops.
Use Cases:
- Canceling HTTP requests on client disconnect.
- Timing out database queries.
- Coordinating multiple goroutines in a pipeline.
15. What are common pitfalls when using goroutines and channels?
Answer:
While Go’s concurrency model is powerful, it’s easy to introduce subtle bugs. Below are common pitfalls and how to avoid them.
1. Goroutine Leaks:
- Problem: Goroutines that never terminate, consuming resources (e.g., waiting on a channel that never sends).
- Example:
ch := make(chan int) go func() { <-ch // Blocks forever if no sender }()
- Solution: Use
context
for cancellation, close channels, or ensure all goroutines have an exit path. - Detection: Monitor
runtime.NumGoroutine()
or use tools likepprof
.
2. Deadlocks:
- Problem: All goroutines are blocked, waiting on each other (e.g., unbuffered channel with no receiver).
- Example:
ch := make(chan int) ch <- 1 // Blocks, no receiver
- Solution: Ensure channels have matching senders/receivers, use buffered channels, or add timeouts.
- Detection: Go’s runtime detects deadlocks and panics with “all goroutines are asleep”.
3. Sending to a Closed Channel:
- Problem: Sending to a closed channel causes a panic.
- Example:
ch := make(chan int) close(ch) ch <- 1 // Panic
- Solution: Use
select
with a default case or ensure senders know when a channel is closed. - Prevention: Close channels in the producer, not the consumer.
4. Overusing Mutexes:
- Problem: Using
sync.Mutex
instead of channels for coordination, leading to complex locking logic. - Example:
var mu sync.Mutex var data int go func() { mu.Lock() data++ mu.Unlock() }()
- Solution: Prefer channels for communication and coordination where possible.
- When to Use Mutex: For protecting shared data with simple read/write patterns.
5. Incorrect Channel Buffer Size:
- Problem: Choosing a buffer size that’s too small (causes blocking) or too large (hides synchronization issues).
- Example:
ch := make(chan int, 1000) // May hide producer/consumer imbalance
- Solution: Start with unbuffered channels, add buffering only when needed, and monitor channel usage.
- Guideline: Buffer size should reflect expected workload and system constraints.
Best Practices:
- Test with
-race
to catch race conditions. - Use
context
for cancellation and timeouts. - Close channels responsibly and avoid sending to closed channels.
- Prefer channels over mutexes for coordination.
- Monitor goroutine counts and channel usage in production.
Bonus Question : Why are goroutines so praised compared to concurrency techniques of other languages?
Answer:
Go’s goroutines are widely praised for their simplicity, efficiency, and performance, particularly when compared to concurrency mechanisms in languages like Java, Python, C++, and Node.js. Below is a detailed comparison focusing on efficiency (resource usage, scalability) and performance (speed, throughput), highlighting why Go’s concurrency model stands out.
Go’s Goroutine Model
- Goroutines: Lightweight, user-space threads managed by the Go runtime, multiplexed onto a small number of OS threads via the M:N scheduler.
- Channels: Provide a safe, idiomatic way to communicate and synchronize, reducing reliance on locks.
- Key Features:
- Small initial stack size (~2KB, grows dynamically).
- Fast creation and context switching (nanoseconds).
- Built-in scheduler with work-stealing and preemption.
- Native support for concurrency patterns like worker pools and pipelines.
Why Goroutines Are Praised
-
Lightweight and Scalable:
- Goroutines use minimal memory (~2KB vs. 1MB for threads), enabling massive concurrency (e.g., millions of goroutines). Java, Python, and C++ threads are limited to thousands due to memory constraints.
- Go’s scheduler automatically scales to available cores, unlike Python’s GIL or Node.js’s single-threaded event loop.
-
Fast Creation and Switching:
- Goroutine creation (~100ns) and context switching are orders of magnitude faster than Java/C++ threads (~10µs) or Python processes (~1ms). They’re competitive with Node.js callbacks and C++ coroutines but more versatile.
- Go’s user-space scheduling avoids OS overhead, unlike Java/C++ threads.
-
Simplified Programming Model:
- Channels provide a safe, high-level abstraction for communication, reducing bugs compared to Java/C++ locks or Python’s multiprocessing IPC.
- Goroutines hide low-level details, unlike Node.js’s explicit async/await or C++’s manual coroutine management.
-
Performance for Mixed Workloads:
- Go handles both CPU- and I/O-bound tasks efficiently, unlike Node.js (I/O-focused) or Python (GIL-limited for CPU tasks). Java and C++ require complex async frameworks for I/O-bound tasks, while Go’s scheduler manages both seamlessly.
- Benchmarks (e.g., HTTP servers) show Go outperforming Java (without async frameworks) and Python for concurrent workloads, with throughput close to C++ but simpler code.
-
Built-in Runtime Support:
- Go’s scheduler, preemption, and garbage collector are optimized for concurrency, unlike C++’s reliance on third-party libraries or Python’s GIL constraints.
- Java’s concurrency utilities (e.g., ExecutorService) are powerful but verbose, while Go’s model is concise and integrated.
Quantitative Example with Others
Consider a server handling 100,000 concurrent connections:
- Go: 100,000 goroutines use ~200MB memory, with fast creation (~100ns each) and high throughput due to multi-core scheduling.
- Java: 100,000 threads use ~100GB, with creation times of ~10µs each, requiring thread pools or async frameworks (e.g., Netty) for efficiency.
- Python: Threading is GIL-limited, multiprocessing uses ~1TB, and AsyncIO struggles with CPU tasks, requiring hybrid approaches.
- C++: Threads use ~100GB; coroutines are lightweight but lack standard scheduling, requiring custom libraries.
- Node.js: Event loop handles I/O well but bottlenecks on CPU tasks, needing worker threads (~100GB).
Conclusion
Goroutines are praised for their lightweight nature, fast performance, and simple programming model, making them more efficient and scalable than Java/C++ threads, Python’s threading/multiprocessing, and Node.js’s event loop for most workloads. Channels and the Go scheduler eliminate much of the complexity of traditional concurrency, enabling developers to write robust, high-performance concurrent programs with ease. While Java and C++ offer powerful concurrency tools, they require more boilerplate and tuning, and Python’s GIL and Node.js’s single-threaded model limit their versatility. Go strikes a unique balance, making it a preferred choice for concurrent systems like servers, microservices, and distributed applications.
[Author: @mdimamhosen Date: 2025-04-22 Category: interview-qa/Higher-Order Tags: [go, First-Order, Higher-Order] ]
First-Order Function and Higher-Order Function
First-Order Function
A first-order function is a function that operates on basic data types (integers, strings, etc.) and does not take other functions as arguments nor returns a function as its result.
Higher-Order Function
A higher-order function is a function that can accept other functions as arguments and/or return a function as its result. Higher-order functions are key in functional programming paradigms.
Example Code
First-Order Function
package main
import "fmt"
// First-order function: does not take or return another function
func add(a int, b int) int {
return a + b
}
func main() {
result := add(5, 3)
fmt.Println("Result:", result) // Output: Result: 8
}
Higher-Order Function
package main
import "fmt"
// Higher-order function: takes a function as an argument
func applyOperation(a int, b int, operation func(int, int) int) int {
return operation(a, b)
}
// Function to be passed as an argument
func multiply(a int, b int) int {
return a * b
}
func main() {
result := applyOperation(5, 3, multiply)
fmt.Println("Result:", result) // Output: Result: 15
}
Logic in Mathematics
In discrete mathematics, logic is used to define and analyze the properties and relationships of objects.
- Object: An entity that has a physical existence (e.g., people, animals).
- Property: Characteristics or attributes of objects (e.g., color, height).
- Relation: Describes how objects are related to each other (e.g., "all customers must pay their pizza bills").
Example:
-
Object: Customer
-
Property: Has a bill
-
Relation: Must pay the bill
-
First-Order Logic: Works with objects, properties, and relations.
-
Higher-Order Logic: Works with relations between functions and operations.
In the context of functions:
- First-Order Function: Operates directly on objects and their properties.
- Higher-Order Function: Operates on relations between functions, allowing for more abstract and flexible operations.
Functional Paradigms
Functional programming is a programming paradigm where programs are constructed by applying and composing functions. It emphasizes pure functions, immutability, and higher-order functions.
- Pure Functions: Functions that always produce the same output for the same input and have no side effects.
- Immutability: Data cannot be changed once it is created. New data structures are created with updated values.
- First-Class Functions: Functions are treated as first-class citizens, meaning they can be assigned to variables, passed as arguments, and returned from other functions.
- Higher-Order Functions: Functions that take other functions as arguments or return them as results.
Functional programming languages like Haskell, Racket, and Lisp provide powerful abstractions for working with functions.
Additional Example Code
Higher-Order Function Returning Another Function
package main
import "fmt"
// Higher-order function: returns another function
func call() func(int, int) {
return add
}
func add(a, b int) {
z := a + b
fmt.Println(z)
}
func main() {
// call() is a higher-order function which returns the function add.
// The returned function is assigned to a variable f, then f is called with arguments 10, 20.
f := call()
f(10, 20) // Output: 30
}
Higher-Order Function with First-Class Functions
package main
import "fmt"
// Higher-order function: accepts another function as an argument
func applyAndReturn(fn func(int, int) int, x int, y int) int {
return fn(x, y)
}
// Function to be passed as an argument
func subtract(a int, b int) int {
return a - b
}
func main() {
result := applyAndReturn(subtract, 10, 5)
fmt.Println("Result:", result) // Output: Result: 5
}
Interview Q&A (Code Examples)
1. What is a higher-order function?
Question: What is a higher-order function, and how does it work in Go?
Answer: A higher-order function is a function that either accepts other functions as parameters or returns a function.
Example:
package main
import "fmt"
func applyOperation(a int, b int, operation func(int, int) int) int {
return operation(a, b)
}
func add(a, b int) int {
return a + b
}
func main() {
result := applyOperation(3, 4, add)
fmt.Println("Result:", result) // Output: Result: 7
}
2. What is a first-order function?
Question: Explain a first-order function in Go.
Answer: A first-order function operates on basic data types and does not take other functions as parameters nor return functions.
Example:
package main
import "fmt"
func add(a int, b int) int {
return a + b
}
func main() {
result := add(3, 5)
fmt.Println("Result:", result) // Output: Result: 8
}
3. Can you create a function that returns another function?
Question: Write a function that returns another function and demonstrates its usage.
Answer: Yes, you can create a higher-order function that returns another function. Here's an example:
package main
import "fmt"
func multiply(a int) func(int) int {
return func(b int) int {
return a * b
}
}
func main() {
multiplyBy2 := multiply(2)
fmt.Println("Result:", multiplyBy2(5)) // Output: Result: 10
}
4. What is an anonymous function in Go?
Question: Show an example of an anonymous function in Go.
Answer: An anonymous function is a function defined without a name, often used for short-lived operations.
Example:
package main
import "fmt"
func main() {
func(a int, b int) {
fmt.Println("Sum:", a+b)
}(3, 4) // Output: Sum: 7
}
5. What is an Immediately Invoked Function Expression (IIFE) in Go?
Question: Write a code example for an Immediately Invoked Function Expression (IIFE) in Go.
Answer: An IIFE is a function that is defined and immediately invoked.
Example:
package main
import "fmt"
func main() {
result := func(a int, b int) int {
return a + b
}(3, 4)
fmt.Println("Result:", result) // Output: Result: 7
}
[Author: @mdimamhosen Date: 2025-04-22 Category: interview-qa/Function Expressions Tags: [go, Function Expressions, Anonymous Functions ] ]
Function Expressions and Anonymous Functions in Go
In Go, functions can be treated as first-class citizens, meaning they can be assigned to variables, passed as arguments, or returned from other functions. These capabilities make Go flexible in terms of handling operations that require dynamic behavior.
Function Expressions
A function expression is when you assign a function to a variable. This allows you to treat the function like any other value in Go, and invoke it using the variable name.
package main
import "fmt"
func main() {
// Assigning a function to a variable
add := func(a int, b int) int {
return a + b
}
// Using the variable to call the function
result := add(3, 4)
fmt.Println("Sum:", result) // Output: Sum: 7
}
Anonymous Functions
An anonymous function is a function that is defined without a name. These are often used for one-off tasks, such as callbacks or short-lived operations.
package main
import "fmt"
func main() {
// Anonymous function without a name
func(message string) {
fmt.Println(message)
}("Hello, Go!") // Output: Hello, Go!
}
Immediately Invoked Function Expressions (IIFE)
In Go, you can also define an anonymous function and immediately invoke it. This is useful for initializing values, performing a quick operation, or executing code that does not need to be reused.
package main
import "fmt"
func main() {
// Immediately Invoked Function Expression (IIFE)
result := func(a int, b int) int {
return a + b
}(3, 4) // Function is invoked immediately with the arguments
fmt.Println("Sum:", result) // Output: Sum: 7
}
More Examples
1. Returning a Function from Another Function
You can return a function from another function, which can then be used later.
package main
import "fmt"
func multiply(factor int) func(int) int {
return func(x int) int {
return x * factor
}
}
func main() {
// Creating a multiplier function with factor 2
multiplyByTwo := multiply(2)
result := multiplyByTwo(5)
fmt.Println("Multiplication Result:", result) // Output: 10
}
2. Using Function Expressions with Map Operations
Function expressions can be used with map functions to process elements in collections.
package main
import "fmt"
func main() {
numbers := []int{1, 2, 3, 4, 5}
// Using a function expression to map each element
doubledNumbers := mapFunc(numbers, func(x int) int {
return x * 2
})
fmt.Println("Doubled Numbers:", doubledNumbers) // Output: [2 4 6 8 10]
}
func mapFunc(numbers []int, f func(int) int) []int {
var result []int
for _, number := range numbers {
result = append(result, f(number))
}
return result
}
Interview Questions and Answers
1. What are function expressions in Go, and how are they useful?
Answer: A function expression is when a function is assigned to a variable. This allows you to treat functions as values and pass them around like other types, enabling dynamic behavior. For instance, you can pass functions as arguments, return them from other functions, and store them in data structures.
2. What is an anonymous function in Go? Give an example.
Answer: An anonymous function is a function without a name. It can be used for quick, short-lived tasks where the function's name is not necessary. Here's an example of an anonymous function:
package main
import "fmt"
func main() {
// Anonymous function used to print a message
func(message string) {
fmt.Println(message)
}("Hello, Go!") // Output: Hello, Go!
}
3. What is the difference between a function expression and a named function?
Answer: A named function has a specific name and can be called by that name. A function expression is an unnamed function assigned to a variable, and the function can be called using that variable. Function expressions offer more flexibility, as you can assign them to variables, pass them around, and invoke them in different contexts.
4. What is an Immediately Invoked Function Expression (IIFE) in Go?
Answer: An Immediately Invoked Function Expression (IIFE) is a function that is defined and called immediately in one expression. This is useful for scenarios where you need to perform a quick operation without the need for a function name or reuse. Example:
package main
import "fmt"
func main() {
// IIFE to perform an immediate calculation
result := func(a int, b int) int {
return a + b
}(3, 4) // Function is invoked immediately
fmt.Println("Sum:", result) // Output: Sum: 7
}
5. How can you pass a function as an argument to another function in Go?
Answer: In Go, you can pass a function as an argument to another function by defining the function signature in the argument list. This allows you to treat the passed function as a value and invoke it within the receiving function.
Example:
package main
import "fmt"
func applyOperation(a int, b int, operation func(int, int) int) int {
return operation(a, b)
}
func main() {
add := func(a int, b int) int {
return a + b
}
result := applyOperation(3, 4, add) // Passing function as argument
fmt.Println("Sum:", result) // Output: Sum: 7
}
[Author: @mdimamhosen Date: 2025-04-20 Category: interview-qa/internal_memory Tags: [go, internal_memory] ]
Internal Memory in Go
In Go, internal memory management is a crucial concept that helps developers understand how the Go runtime handles memory allocation and execution. This includes understanding the code segment, data segment, stack, and heap.
Code Segment
The code segment contains all the functions and executable instructions of a program. It is a read-only section of memory where the compiled code resides. This segment is loaded into memory when the program starts.
Example:
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
In this example, the main
function and the fmt.Println
function are part of the code segment.
Data Segment
The data segment contains all the global and static variables. These variables are initialized before the program starts executing and remain in memory throughout the program's lifecycle.
Example:
package main
import "fmt"
var globalVar = "I am a global variable"
func main() {
fmt.Println(globalVar)
}
Here, globalVar
resides in the data segment.
Stack Segment
The stack segment is used for function calls, local variables, and control flow. When a function is called, a stack frame is created in the stack segment. This stack frame contains the function's local variables and return address. The stack is managed in a Last In, First Out (LIFO) manner.
Example:
package main
import "fmt"
func add(a int, b int) int {
return a + b
}
func main() {
result := add(5, 3)
fmt.Println("Result:", result)
}
In this example, when add
is called, a stack frame is created for its local variables a
and b
.
Heap Segment
The heap segment is used for dynamic memory allocation. Memory allocated on the heap is managed by the garbage collector in Go. Variables in the heap have a longer lifetime compared to stack variables.
Example:
package main
import "fmt"
func main() {
ptr := new(int) // Allocates memory on the heap
*ptr = 42
fmt.Println("Value:", *ptr)
}
Here, ptr
points to a memory location on the heap where the value 42
is stored.
Initialization and Execution
When a Go program starts, it first looks for init
functions. If any init
functions are present, they are executed before the main
function. The init
functions are used for initializing global variables or performing setup tasks.
Example:
package main
import "fmt"
var globalVar string
func init() {
globalVar = "Initialized in init function"
fmt.Println("Init function executed")
}
func main() {
fmt.Println(globalVar)
}
In this example, the init
function initializes the globalVar
before the main
function is executed.
Summary
- Code Segment: Contains all the functions and executable instructions.
- Data Segment: Contains global and static variables.
- Stack Segment: Used for function calls and local variables.
- Heap Segment: Used for dynamic memory allocation.
- Init Function: Executed before the
main
function for initialization tasks.
Code Execution Phases
Phases of Code Execution
- Compile the code and generate the binary file:
go build main.go
- Run the binary file:
./main
Internal Memory Execution
Code Segment
- Holds the compiled code of the program.
- The code segment is read-only and cannot be modified at runtime.
- The code segment is loaded into memory when the program is executed.
- The code segment is divided into two parts:
- Text segment: Holds the compiled code of the program.
- Data segment: Holds the initialized and uninitialized data of the program.
- The code segment is a static memory allocation.
- The code segment is allocated at compile time and is fixed in size.
- The code segment is used for the program code and constants.
- The code segment is shared among all processes.
- The code segment is not writable and cannot be modified at runtime.
Data Segment
- Holds the global variables and constants.
- The data segment is divided into two parts:
- Initialized data segment: Holds the initialized global variables and constants.
- Uninitialized data segment: Holds the uninitialized global variables and constants.
- The data segment is a static memory allocation.
- The data segment is allocated at compile time and is fixed in size.
- The data segment is used for global variables and constants.
Stack Segment
- Holds the local variables and function calls.
- Each function call creates a new stack frame.
- When a function call is completed, its stack frame is removed from the stack.
- The stack grows and shrinks as functions are called and return.
- The stack is a LIFO (Last In First Out) data structure.
- The stack is used for function calls, local variables, and control flow.
- The stack is a dynamic memory allocation.
- The stack is allocated at runtime and can grow and shrink as needed.
- The stack is not shared among processes.
- The stack is writable and can be modified at runtime.
- The stack is used for local variables and function calls.
Heap Segment
- Holds the dynamically allocated memory.
- The heap is a dynamic memory allocation.
- The heap is allocated at runtime and can grow and shrink as needed.
- The heap is shared among processes.
- The heap is writable and can be modified at runtime.
- The heap is used for dynamically allocated memory.
Escape Analysis
- If the variable is declared inside a function, it will be stored in the stack segment.
- If the variable is declared outside a function, it will be stored in the data segment.
- If the variable is declared inside a function and it is returned from the function, it will be stored in the heap segment.
- If the variable is declared inside a function and it is not returned from the function, it will be stored in the stack segment.
Common Interview Questions on Internal Memory in Go
1. What is the difference between stack and heap memory?
Answer:
- Stack: Used for function calls and local variables. It is faster but has limited size.
- Heap: Used for dynamic memory allocation. It is slower but has a larger size.
2. How does Go manage memory allocation?
Answer: Go uses garbage collection to manage memory allocation. The garbage collector automatically frees memory that is no longer in use.
3. What is escape analysis in Go?
Answer: Escape analysis determines whether a variable should be allocated on the stack or the heap. If a variable "escapes" the function, it is allocated on the heap.
4. What is the purpose of the init
function in Go?
Answer:
The init
function is used for initializing global variables or performing setup tasks before the main
function is executed.
5. Can the code segment be modified at runtime?
Answer: No, the code segment is read-only and cannot be modified at runtime.
6. What happens if the stack memory is exceeded?
Answer: If the stack memory is exceeded, a stack overflow error occurs.
7. How does Go handle dynamic memory allocation?
Answer:
Go uses the new
and make
functions for dynamic memory allocation. The garbage collector manages the memory.
8. What is the difference between new
and make
in Go?
Answer:
new
: Allocates memory and returns a pointer.make
: Initializes slices, maps, and channels.
9. How are global variables stored in memory?
Answer: Global variables are stored in the data segment of memory.
10. What is the role of the garbage collector in Go?
Answer: The garbage collector automatically frees memory that is no longer in use, preventing memory leaks.
Example Code for Escape Analysis
package main
import "fmt"
func createPointer() *int {
num := 42
return &num // Escapes to heap
}
func main() {
ptr := createPointer()
fmt.Println(*ptr)
}
In this example, the variable num
escapes to the heap because it is returned from the function createPointer
.
[Author: @mdimamhosen Date: 2025-04-19 Category: interview-qa/logical_operators Tags: [go, logical_operators] ]
Logical Operators
Logical operators are used to determine the logic between variables or values.
1. Logical and (&&)
Returns true if both statements are true
2. Logical or (||)
Returns true if one statements is true
3. Logical not (!)
Reverse the result, returns false if the result is true
package main
import "fmt"
func main() {
fmt.Println(true && true) // true
fmt.Println(true && false) // false
fmt.Println(true || true) // true
fmt.Println(false || false) // false
fmt.Println(!true) // false
fmt.Println(!false) // true
}
Frequently Asked Questions
1. What is the difference between &&
and ||
in Go?
Answer:
&&
(Logical AND) returns true only if both conditions are true.||
(Logical OR) returns true if at least one condition is true.
Code Example:
package main
import "fmt"
func main() {
fmt.Println(true && false) // false
fmt.Println(true || false) // true
}
2. How does the !
operator work in Go?
Answer:
- The
!
(Logical NOT) operator reverses the boolean value.
Code Example:
package main
import "fmt"
func main() {
fmt.Println(!true) // false
fmt.Println(!false) // true
}
3. Can logical operators be used with non-boolean values?
Answer:
- No, logical operators in Go work only with boolean values.
4. How can I combine multiple logical operators in a single expression?
Answer:
- You can combine them using parentheses to control precedence.
Code Example:
package main
import "fmt"
func main() {
fmt.Println((true && false) || true) // true
}
5. What is the precedence of logical operators in Go?
Answer:
!
has the highest precedence, followed by&&
, and then||
.
Code Example:
package main
import "fmt"
func main() {
fmt.Println(!true || false && true) // false
}
6. How can I use logical operators in conditional statements?
Answer:
- Logical operators are often used in
if
statements to combine conditions.
Code Example:
package main
import "fmt"
func main() {
if true && !false {
fmt.Println("Condition met")
}
}
7. Can logical operators short-circuit in Go?
Answer:
- Yes,
&&
and||
short-circuit. For example,&&
stops evaluating if the first condition is false.
Code Example:
package main
import "fmt"
func main() {
fmt.Println(false && (5 > 3)) // false (5 > 3 is not evaluated)
}
8. How can I debug logical expressions in Go?
Answer:
- Use
fmt.Println
to print intermediate results.
Code Example:
package main
import "fmt"
func main() {
condition1 := true
condition2 := false
fmt.Println(condition1 && condition2) // false
}
9. Can logical operators be used in loops?
Answer:
- Yes, they can be used in loop conditions.
Code Example:
package main
import "fmt"
func main() {
for i := 0; i < 10 && i%2 == 0; i++ {
fmt.Println(i)
}
}
10. What happens if I use logical operators with nil values?
Answer:
- Logical operators cannot be directly used with
nil
. You need to comparenil
explicitly.
Code Example:
package main
import "fmt"
func main() {
var ptr *int = nil
fmt.Println(ptr == nil || true) // true
}
[Author: @mdimamhosen Date: 2025-04-19 Category: e.g., interview-qa/topic_name Tags: [go, concurrency, channels] ]
While Loop
Unlike other programming languages, Go doesn't have a dedicated keyword for a while loop. However, we can use the for loop to perform the functionality of a while loop.
// Program to print numbers between 0 and 10
package main
import ("fmt")
func main() {
number := 0
for number <= 10 {
fmt.Println(number)
number++
}
}
Frequently Asked Questions
1. How can we implement an infinite loop in Go?
Answer: In Go, an infinite loop can be implemented using the for
loop without any condition.
package main
import ("fmt")
func main() {
for {
fmt.Println("This is an infinite loop")
}
}
2. How do you break out of a loop in Go?
Answer: Use the break
statement to exit a loop prematurely.
package main
import ("fmt")
func main() {
for i := 0; i < 10; i++ {
if i == 5 {
break
}
fmt.Println(i)
}
}
3. How do you skip an iteration in a loop in Go?
Answer: Use the continue
statement to skip the current iteration and move to the next one.
package main
import ("fmt")
func main() {
for i := 0; i < 10; i++ {
if i%2 == 0 {
continue
}
fmt.Println(i)
}
}
4. Can we use labels with loops in Go?
Answer: Yes, labels can be used to control nested loops.
package main
import ("fmt")
func main() {
OuterLoop:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if i == 1 && j == 1 {
break OuterLoop
}
fmt.Println(i, j)
}
}
}
5. How do you implement a do-while loop in Go?
Answer: Go does not have a do-while
loop, but it can be simulated using a for
loop.
package main
import ("fmt")
func main() {
number := 0
for {
fmt.Println(number)
number++
if number > 5 {
break
}
}
}
6. How can you iterate over a slice in Go?
Answer: Use the range
keyword to iterate over a slice.
package main
import ("fmt")
func main() {
numbers := []int{1, 2, 3, 4, 5}
for index, value := range numbers {
fmt.Printf("Index: %d, Value: %d\n", index, value)
}
}
7. How do you iterate over a map in Go?
Answer: Use the range
keyword to iterate over a map.
package main
import ("fmt")
func main() {
myMap := map[string]int{"a": 1, "b": 2, "c": 3}
for key, value := range myMap {
fmt.Printf("Key: %s, Value: %d\n", key, value)
}
}
8. How do you iterate over a string in Go?
Answer: Use the range
keyword to iterate over a string.
package main
import ("fmt")
func main() {
str := "hello"
for index, char := range str {
fmt.Printf("Index: %d, Character: %c\n", index, char)
}
}
9. How do you use a loop to calculate the factorial of a number in Go?
Answer: Use a for
loop to calculate the factorial.
package main
import ("fmt")
func main() {
number := 5
factorial := 1
for i := 1; i <= number; i++ {
factorial *= i
}
fmt.Println("Factorial:", factorial)
}
10. How do you use a loop to reverse a slice in Go?
Answer: Use a for
loop to swap elements in the slice.
package main
import ("fmt")
func main() {
numbers := []int{1, 2, 3, 4, 5}
for i, j := 0, len(numbers)-1; i < j; i, j = i+1, j-1 {
numbers[i], numbers[j] = numbers[j], numbers[i]
}
fmt.Println("Reversed Slice:", numbers)
}
[Author: @mdimamhosen Date: 2025-04-19 Category: interview-qa/maps Tags: [go, maps, data-structure] ]
Maps
Maps are a data structure which allow us to store data values in key:value pairs.
A map is an unordered and changeable collection that does not allow duplicates.
The default value of a map is nil
.
userInfo := map[string]int{
"huxn": 17,
"alex": 18,
"john": 27,
}
fmt.Println(userInfo)
userInfo["jordan"] = 15
fmt.Println(userInfo["huxn"])
fmt.Println(userInfo["alex"])
fmt.Println(userInfo["john"])
Frequently Asked Questions
1. How do you create a map in Go?
Answer:
You can create a map using the make
function or by using a map literal.
Code Example:
// Using make function
userInfo := make(map[string]int)
userInfo["huxn"] = 17
userInfo["alex"] = 18
fmt.Println(userInfo)
// Using map literal
userInfo := map[string]int{
"huxn": 17,
"alex": 18,
}
fmt.Println(userInfo)
2. How do you check if a key exists in a map?
Answer: You can use the second return value of a map lookup to check if a key exists.
Code Example:
userInfo := map[string]int{
"huxn": 17,
"alex": 18,
}
value, exists := userInfo["huxn"]
if exists {
fmt.Println("Key exists with value:", value)
} else {
fmt.Println("Key does not exist")
}
3. How do you delete a key from a map?
Answer:
You can use the delete
function to remove a key from a map.
Code Example:
userInfo := map[string]int{
"huxn": 17,
"alex": 18,
}
delete(userInfo, "huxn")
fmt.Println(userInfo)
4. Can a map key be of any type?
Answer: No, map keys must be of a type that is comparable (e.g., strings, integers, etc.).
Code Example:
// Valid keys
userInfo := map[string]int{
"huxn": 17,
"alex": 18,
}
// Invalid keys (e.g., slices)
// userInfo := map[[]int]int{} // This will throw an error
5. How do you iterate over a map?
Answer:
You can use a for
loop with the range
keyword to iterate over a map.
Code Example:
userInfo := map[string]int{
"huxn": 17,
"alex": 18,
}
for key, value := range userInfo {
fmt.Printf("Key: %s, Value: %d\n", key, value)
}
6. What is the zero value of a map?
Answer:
The zero value of a map is nil
.
Code Example:
var userInfo map[string]int
fmt.Println(userInfo == nil) // true
7. Can you compare two maps in Go?
Answer: No, maps cannot be compared directly. You need to compare them manually by iterating over their keys and values.
Code Example:
map1 := map[string]int{"huxn": 17, "alex": 18}
map2 := map[string]int{"huxn": 17, "alex": 18}
// Direct comparison is not allowed
// fmt.Println(map1 == map2) // This will throw an error
// Manual comparison
areEqual := true
for key, value := range map1 {
if map2[key] != value {
areEqual = false
break
}
}
fmt.Println("Maps are equal:", areEqual)
8. How do you find the length of a map?
Answer:
You can use the len
function to find the number of key-value pairs in a map.
Code Example:
userInfo := map[string]int{
"huxn": 17,
"alex": 18,
}
fmt.Println("Length of map:", len(userInfo))
9. Can you nest maps in Go?
Answer: Yes, you can create a map where the value is another map.
Code Example:
nestedMap := map[string]map[string]int{
"group1": {
"huxn": 17,
"alex": 18,
},
"group2": {
"john": 27,
},
}
fmt.Println(nestedMap)
10. How do you copy a map in Go?
Answer: You need to manually copy the key-value pairs from one map to another.
Code Example:
originalMap := map[string]int{
"huxn": 17,
"alex": 18,
}
copiedMap := make(map[string]int)
for key, value := range originalMap {
copiedMap[key] = value
}
fmt.Println("Original Map:", originalMap)
fmt.Println("Copied Map:", copiedMap)
[Author: @mdimamhosen Date: 2025-04-19 Category: interview-qa/operators Tags: [go, operators, arithmetic, assignment] ]
Operators are used to perform operations on variables and values
Arithmetic Operators
1. Addition: The + operator adds two operands. For example, x+y.
2. Subtraction: The - operator subtracts two operands. For example, x-y.
3. Multiplication: The * operator multiplies two operands. For example, x*y.
4. Division: The / operator divides the first operand by the second. For example, x/y.
5. Modulus: Returns the division remainder
6. Increment: The ++ Increases the value of a variable by 1
7. Decrement: The -- Decreases the value of a variable by 1
package main
import "fmt"
func main() {
fmt.Println(2 + 2) // 4
fmt.Println(2 - 2) // 0
fmt.Println(2 * 2) // 4
fmt.Println(2 / 2) // 1
fmt.Println(2 % 2) // 0
}
Increment
package main
import ("fmt")
func main() {
x:= 10
x++ // Add one new value (increment)
fmt.Println(x)
}
Decrement
package main
import ("fmt")
func main() {
x:= 10
x-- // Remove one new value (decrement)
fmt.Println(x)
}
Assignment Operators
Assignment operators are used to assign values to variables.
Operator | Example | Same As |
---|---|---|
= | x = 5 | x = 5 |
+= | x += 3 | x = x + 3 |
-= | x -= 3 | x = x - 3 |
*= | x *= 3 | x = x * 3 |
/= | x /= 3 | x = x / 3 |
%= | x %= 3 | x = x % 3 |
Questions and Examples
1. Create a variable named lgNumber
, store 1000 as a value, and perform various operations.
package main
import ("fmt")
func main() {
lgNumber := 1000
// Add that variable with itself
sum := lgNumber + lgNumber
fmt.Println("Addition:", sum) // 2000
// Subtract that variable by itself
difference := lgNumber - lgNumber
fmt.Println("Subtraction:", difference) // 0
// Multiply that variable with itself
product := lgNumber * lgNumber
fmt.Println("Multiplication:", product) // 1000000
// Divide that variable with itself
quotient := lgNumber / lgNumber
fmt.Println("Division:", quotient) // 1
}
Frequently Asked Questions
1. How do you perform addition and subtraction in Go?
Answer: Use the +
operator for addition and -
for subtraction.
package main
import "fmt"
func main() {
a, b := 10, 5
fmt.Println("Addition:", a+b) // 15
fmt.Println("Subtraction:", a-b) // 5
}
2. How do you calculate the remainder of a division in Go?
Answer: Use the %
operator for modulus.
package main
import "fmt"
func main() {
fmt.Println("Remainder:", 10%3) // 1
}
3. Can you increment a variable in Go?
Answer: Yes, use ++
to increment a variable by 1.
package main
import "fmt"
func main() {
x := 5
x++
fmt.Println("Incremented Value:", x) // 6
}
4. How do you assign and add a value to a variable in Go?
Answer: Use the +=
operator.
package main
import "fmt"
func main() {
x := 10
x += 5
fmt.Println("Updated Value:", x) // 15
}
5. How do you multiply and assign a value to a variable in Go?
Answer: Use the *=
operator.
package main
import "fmt"
func main() {
x := 10
x *= 2
fmt.Println("Updated Value:", x) // 20
}
6. How do you divide and assign a value to a variable in Go?
Answer: Use the /=
operator.
package main
import "fmt"
func main() {
x := 10
x /= 2
fmt.Println("Updated Value:", x) // 5
}
7. How do you decrement a variable in Go?
Answer: Use --
to decrement a variable by 1.
package main
import "fmt"
func main() {
x := 5
x--
fmt.Println("Decremented Value:", x) // 4
}
8. How do you perform multiple arithmetic operations in one line?
Answer: Combine operators in a single expression.
package main
import "fmt"
func main() {
result := (10 + 5) * 2 - 3
fmt.Println("Result:", result) // 27
}
9. How do you check if a number is even or odd in Go?
Answer: Use the modulus operator %
.
package main
import "fmt"
func main() {
num := 7
if num%2 == 0 {
fmt.Println("Even")
} else {
fmt.Println("Odd")
}
}
10. How do you swap two numbers without using a third variable in Go?
Answer: Use arithmetic operations.
package main
import "fmt"
func main() {
a, b := 5, 10
a = a + b
b = a - b
a = a - b
fmt.Println("Swapped Values:", a, b) // 10, 5
}
[Author: @mdimamhosen Date: 2025-04-22 Category: interview-qa/Argument vs Parameter Tags: [go, Parameter, Argument] ]
Difference between Parameter and Argument
Parameter
A parameter is a variable in the declaration of a function. It defines what kind of input a function will accept when it is called. It acts as a placeholder for the values that will be passed into the function.
Argument
An argument is the actual value that is passed into the function when it is called. Arguments correspond to the parameters defined in the function signature. These are the real values provided to the function when executing the code.
Example Code
package main
import "fmt"
// Function with parameters 'a' and 'b'
func add(a int, b int) int {
return a + b
}
func main() {
// Calling the function with arguments 5 and 3
result := add(5, 3)
fmt.Println("Result:", result) // Output: Result: 8
}
In the above example:
a
andb
are parameters of theadd
function.5
and3
are arguments passed to theadd
function when it is called in themain
function.
Further Explanation
Parameters are declared within the function's signature. They provide the function with input values that can be used within the function's body.
Arguments are provided when the function is called. The values of these arguments are assigned to the corresponding parameters, allowing the function to perform its operation based on those values.
Types of Parameters
- Formal Parameters: These are parameters that appear in the function definition. They are used to represent the expected values inside the function.
- Actual Parameters: These are arguments that are passed during the function call.
Interview Questions and Answers
1. What is the difference between pass-by-value and pass-by-reference in function arguments?
Answer:
- Pass-by-value: The function gets a copy of the argument's value. Changes made to the parameter do not affect the original argument.
- Pass-by-reference: The function gets a reference (memory address) to the argument, so any changes made to the parameter directly affect the original argument.
Code Example:
package main
import "fmt"
// Pass-by-value
func modifyValue(x int) {
x = 20
}
// Pass-by-reference
func modifyReference(x *int) {
*x = 20
}
func main() {
a := 10
modifyValue(a)
fmt.Println("After modifyValue:", a) // Output: 10 (no change)
modifyReference(&a)
fmt.Println("After modifyReference:", a) // Output: 20 (value changed)
}
2. How do you handle default arguments in Go?
Answer: Go does not support default arguments directly. Instead, you can achieve default values using variadic functions or by explicitly checking if a value is provided.
Code Example:
package main
import "fmt"
func greet(name string, message string) {
if message == "" {
message = "Hello" // default message
}
fmt.Println(message, name)
}
func main() {
greet("John", "") // Output: Hello John
greet("Jane", "Hi") // Output: Hi Jane
}
3. What is a variadic function, and how is it used?
Answer:
A variadic function is a function that takes a variable number of arguments. It is defined using ...
in the parameter list. This allows you to pass any number of arguments.
Code Example:
package main
import "fmt"
func sum(numbers ...int) int {
total := 0
for _, num := range numbers {
total += num
}
return total
}
func main() {
fmt.Println(sum(1, 2, 3)) // Output: 6
fmt.Println(sum(10, 20, 30, 40)) // Output: 100
}
4. What will happen if a function is called with more arguments than its parameters?
Answer: In Go, if the number of arguments passed to a function exceeds the number of parameters declared, the code will result in a compile-time error. Go checks the number of arguments and parameters at compile-time, and any mismatch in the number of arguments will cause an error.
Code Example:
package main
import "fmt"
func greet(name string) {
fmt.Println("Hello, ", name)
}
func main() {
greet("John", "Doe") // Compile-time error: too many arguments
}
5. Can you return multiple values from a function in Go?
Answer: Yes, Go allows a function to return multiple values. You can return multiple values of different types from a function.
Code Example:
package main
import "fmt"
// Function returning two values
func divide(a, b int) (int, int) {
return a / b, a % b
}
func main() {
quotient, remainder := divide(10, 3)
fmt.Println("Quotient:", quotient) // Output: Quotient: 3
fmt.Println("Remainder:", remainder) // Output: Remainder: 1
}
[Author: @jahidprog
Date: 2025-04-26
Category: interview-qa/pointers
Tags: [go, pointers, memory-management, performance]
Pointers in Golang
A pointer is a variable that stores the memory address of another variable. Pointers are used to:
- Avoid copying large amounts of data
- Allow functions to modify the actual value of variables
- Improve program performance
We use pointers when we want to work with the actual data instead of working on copies.
Pointer Basics
1. How to Declare a Pointer
Use *
before the type to declare a pointer.
package main
import "fmt"
func main() {
var num int = 42
var ptr *int = &num // ptr holds the memory address of num
fmt.Println("Address:", ptr) // e.g., 0xc000018030
fmt.Println("Value:", *ptr) // 42 (dereferencing)
}
2. Zero Value of a Pointer
Uninitialized pointers have a nil
value.
package main
import "fmt"
func main() {
var ptr *int
fmt.Println(ptr) // <nil>
}
3. Pointer vs Normal Variable
Feature | Normal Variable | Pointer |
---|---|---|
Storage | Holds value | Holds memory address |
Modification | Works on copy | Modifies original data |
Frequently Asked Questions
1. What is a pointer in Go?
Answer: A variable that stores the memory address of another variable.
var x int = 10
var ptr *int = &x // ptr points to x
2. How do you declare a pointer?
Answer: Use *datatype
.
var ptr *string
3. What is the zero value of a pointer?
Answer: nil
.
4. How is a pointer different from a normal variable?
Answer:
- Normal variable: Stores value directly
- Pointer: Stores memory address of another variable
5. Does Go support pointer arithmetic like C?
Answer: No, Go deliberately omits pointer arithmetic for safety.
6. How to pass a pointer to a function?
Answer: Use *type
parameter.
package main
import "fmt"
func modify(ptr *int) {
*ptr = 100
}
func main() {
x := 50
modify(&x)
fmt.Println(x) // 100
}
7. Why use pointers for large structs?
Answer: Avoids expensive data copying.
type BigStruct struct { /* many fields */ }
func process(b *BigStruct) {
// Operates on original struct
}
8. How to create a pointer to a struct?
Answer: Use &
operator.
user := User{Name: "Alice"}
userPtr := &user
9. Can you have a pointer to a pointer?
Answer: Yes (double indirection).
a := 10
p1 := &a
p2 := &p1
fmt.Println(**p2) // 10
10. How to check if a pointer is nil?
Answer: Compare with nil
.
if ptr == nil {
fmt.Println("Pointer is nil")
}
11. How do pointers help with memory efficiency?
Answer: They allow sharing data without duplication.
largeData := make([]byte, 1e6) // 1MB data
processData(&largeData) // Pass address (8 bytes) instead of copying 1MB
12. What's the difference between *
and &
?
Answer:
&
gets the address of a variable*
dereferences a pointer to access the value
x := 5
ptr := &x // ptr holds address of x
val := *ptr // val gets 5
13. When should you avoid pointers?
Answer:
- With small data types (int, bool etc.) where copying is cheap
- When immutability is desired
- In concurrency scenarios where shared access could cause races
14. How do pointers relate to Go's garbage collection?
Answer: The GC tracks pointers to determine object reachability. Unreachable objects (no pointers to them) get collected.
15. Can you use pointers with interfaces?
Answer: Yes, but the rules differ:
var w io.Writer
buf := new(bytes.Buffer)
w = buf // No explicit pointer needed
Key Takeaways:
- Pointers provide direct memory access
- Use
&
to get addresses,*
to dereference - Essential for efficient large data handling
- Go pointers are safer than C (no arithmetic)
[Author: @mdimamhosen Date: 2025-04-22 Category: interview-qa/Receiver Function Tags: [go, Receiver Function] ]
📦 Receiver Function in Go
A receiver function in Go is a method bound to a specific type—typically a struct. It enables you to implement object-oriented behavior by defining methods on user-defined types.
🧱 Struct and Receiver Basics
Struct Definition
// User struct with basic fields
type User struct {
Name string
Age int
}
📞 Regular Function vs Receiver Function
Regular Function
func printUser(user User) {
fmt.Println("User Name:", user.Name)
fmt.Println("User Age:", user.Age)
}
This is a standalone function that takes User
as a parameter.
Value Receiver Method
func (u User) printDetails() {
fmt.Println("Name:", u.Name)
fmt.Println("Age:", u.Age)
}
Here, printDetails()
is associated with User
type using a value receiver. It works on a copy, so original data won’t change.
Pointer Receiver Method
func (u *User) updateAge(newAge int) {
u.Age = newAge
}
This method modifies the original User
struct because it uses a pointer receiver.
✅ Main Function with Usage
func main() {
user1 := User{Name: "John", Age: 30}
user2 := User{Name: "Jane", Age: 25}
// Regular function call
printUser(user1)
// Receiver function calls
user1.printDetails()
user2.printDetails()
// Update age using pointer receiver
user1.updateAge(35)
fmt.Println("Updated Age of user1:", user1.Age)
// Demonstrate value receiver (no change to original)
user2.call(100)
fmt.Println("User2's age after call():", user2.Age)
}
🔍 Additional Receiver Method
// Value receiver that does not affect original struct
func (u User) call(age int) {
u.Age = age
fmt.Println("Inside call() - temporary age:", u.Age)
}
This will not change the actual User.Age
outside the function.
🧪 Example Output
User Name: John
User Age: 30
Name: John
Age: 30
Name: Jane
Age: 25
Updated Age of user1: 35
Inside call() - temporary age: 100
User2's age after call(): 25
💡 Key Takeaways
- ✅ Value receivers are good for read-only operations.
- ✅ Pointer receivers are used when you want to modify the actual data.
- ✅ Go supports object-like behavior through receiver functions.
- ✅ Methods with pointer receivers can be called on both values and pointers.
10 Interview Questions and Answers
-
What is a receiver function in Go?
- A receiver function is a method associated with a specific type, allowing you to define methods on structs or other types.
-
What is the difference between a value receiver and a pointer receiver?
- A value receiver operates on a copy of the object, while a pointer receiver operates on the actual object, allowing modifications.
-
Can you define multiple receiver functions for the same type?
- Yes, you can define multiple receiver functions for the same type.
-
What is the syntax for defining a receiver function?
func (receiverType TypeName) methodName(parameters) {}
-
Can receiver functions be used with built-in types?
- No, receiver functions can only be defined for user-defined types.
-
What happens if you call a value receiver function on a pointer?
- Go automatically dereferences the pointer, so the function works as expected.
-
What is the purpose of receiver functions?
- They enable object-oriented programming by associating methods with types.
-
Can a receiver function modify the original object?
- Only if it uses a pointer receiver.
-
What is the difference between a regular function and a receiver function?
- A regular function is not associated with any type, while a receiver function is tied to a specific type.
-
Can you use receiver functions with interfaces?
- Yes, receiver functions are often used to implement interface methods.
Example Output
User Name: John
User Age: 30
User Name: Jane
User Age: 25
User Age: 10
User Age: 20
[Author: @mdimamhosen Date: 2025-04-22 Category: interview-qa/Scope Tags: [go, Scope] ]
Go Language: Understanding Scope
Introduction
In Go (Golang), scope refers to the region in the code where a variable, function, or constant is accessible. The scope determines the visibility and lifetime of variables and functions, which is essential for understanding how the Go compiler handles symbol resolution.
There are several types of scopes in Go:
- Package Scope: Variables or functions defined at the package level.
- Function Scope: Variables defined within a function.
- Block Scope: Variables defined inside a block of code, such as within loops, if-statements, etc.
- Global Scope: Variables or functions accessible throughout the entire program.
This document will explore these different types of scope with code examples and will also cover common pitfalls and best practices related to variable scope in Go.
Types of Scope in Go
1. Package Scope
In Go, the package scope refers to variables or functions that are accessible throughout the package in which they are declared. They can be accessed from any function within the package.
Example: Package Scope
package main
import "fmt"
// Global variable (Package Scope)
var globalVar = 10
func printGlobalVar() {
// Accessing package-scoped variable
fmt.Println("Global Variable:", globalVar)
}
func main() {
printGlobalVar() // Output: Global Variable: 10
}
In the above example, globalVar
is accessible within the main
and printGlobalVar
functions because it is defined at the package level.
2. Function Scope
Variables declared inside a function are local to that function and cannot be accessed outside of it. This is called function scope.
Example: Function Scope
package main
import "fmt"
func myFunction() {
// Variable inside the function
var functionVar = "I am local to the function"
fmt.Println(functionVar) // Output: I am local to the function
}
func main() {
// Un-commenting the next line would cause an error
// fmt.Println(functionVar) // Error: undefined functionVar
myFunction()
}
In the example above, the variable functionVar
is only available inside the myFunction()
and cannot be accessed from main()
.
3. Block Scope
Block scope refers to variables declared inside a block of code, such as within if
statements, loops, or other code blocks.
Example: Block Scope
package main
import "fmt"
func main() {
if true {
// Variable inside the block
var blockVar = "I exist only within this block"
fmt.Println(blockVar) // Output: I exist only within this block
}
// Un-commenting the next line would cause an error
// fmt.Println(blockVar) // Error: undefined blockVar
}
The variable blockVar
is only accessible within the if
block where it is declared. Attempting to use it outside the block will result in a compile-time error.
4. Global Scope (Cross-package Scope)
In Go, global variables (package-level variables) can be shared across multiple files within the same package, but they cannot be accessed by other packages unless explicitly exported.
Example: Cross-file Scope
// file1.go
package main
import "fmt"
var sharedVar = "This is a shared variable"
func displaySharedVar() {
fmt.Println(sharedVar)
}
// file2.go
package main
func main() {
displaySharedVar() // Output: This is a shared variable
}
In this case, the variable sharedVar
is accessible across multiple files because it is within the same package.
Rules of Scope in Go
- Variable Shadowing: When a local variable has the same name as a variable in an outer scope, the local variable "shadows" the outer variable.
- Exported Variables: Variables that start with an uppercase letter are exported and accessible from other packages. Lowercase variables are private to the package.
- Short Declaration: The
:=
operator can be used for declaring and initializing variables in a more concise manner within functions or blocks.
Common Pitfalls in Scope
-
Variable Shadowing: When a variable in an inner scope has the same name as a variable in an outer scope, the inner variable shadows the outer one. This can lead to unintended behavior.
package main import "fmt" var x = 10 func main() { var x = 20 // Shadows outer x fmt.Println(x) // Output: 20 } fmt.Println(x) // Output: 10
-
Accessing Unexported Variables: If a variable is declared with a lowercase first letter, it is not accessible from other packages.
package main import "fmt" var unexportedVar = "I am private" func main() { fmt.Println(unexportedVar) // Accessible within the same package }
5 Interview Questions with Code
Q1: What is the scope of a variable declared inside a for loop?
Code:
package main
import "fmt"
func main() {
for i := 0; i < 3; i++ {
var loopVar = "Loop variable"
fmt.Println(loopVar)
}
// Uncommenting the line below will cause an error because loopVar is out of scope
// fmt.Println(loopVar) // Error: undefined loopVar
}
Answer: The variable loopVar
is scoped to the for
loop and cannot be accessed outside of it.
Q2: What happens if you declare a variable with the same name in different scopes?
Code:
package main
import "fmt"
var x = 10
func main() {
fmt.Println(x) // Output: 10
var x = 20 // Shadows the outer x
fmt.Println(x) // Output: 20
}
Answer: The inner variable x
shadows the outer one within the scope of the main()
function.
Q3: How does the :=
operator work in Go with variable scope?
Code:
package main
import "fmt"
func main() {
var a = 5
fmt.Println(a) // Output: 5
a := 10 // Short declaration: Creates a new a variable within main's scope
fmt.Println(a) // Output: 10
}
Answer: The :=
operator creates a new variable in the local scope, shadowing the outer variable a
.
Q4: How does Go handle global scope variables across multiple files?
Code:
// file1.go
package main
import "fmt"
var globalVar = "Global variable"
func displayGlobalVar() {
fmt.Println(globalVar)
}
// file2.go
package main
func main() {
displayGlobalVar() // Output: Global variable
}
Answer: The variable globalVar
is accessible across multiple files within the same package.
Q5: What is the significance of variable naming conventions in Go?
Code:
package main
import "fmt"
// Exported variable (visible outside the package)
var ExportedVar = "I am exported"
// Unexported variable (private to the package)
var unexportedVar = "I am unexported"
func main() {
fmt.Println(ExportedVar) // Accessible
fmt.Println(unexportedVar) // Accessible within the same package
}
Answer: In Go, variables that start with an uppercase letter are exported and can be accessed outside the package, while variables that start with a lowercase letter are unexported and private to the package.
[Author: @mdimamhosen Date: 2025-04-19 Category: interview-qa/slices Tags: [go, slices, arrays, make]
Slices
Slices are also used to store multiple values of the same type in a single variable, however unlike arrays, the length of a slice can grow and shrink as you see fit.
There are several ways to create a slice 👇
- Using the
[]datatype{values}
format - Create a slice from an array
- Using the
make()
function
// name := []datatype{values}
// name := []int{}
package main
import ("fmt")
func main() {
myslice1 := []int{}
fmt.Println(len(myslice1))
fmt.Println(cap(myslice1))
fmt.Println(myslice1)
myslice2 := []string{"Go", "Slices", "Are", "Powerful"}
fmt.Println(len(myslice2))
fmt.Println(cap(myslice2))
fmt.Println(myslice2)
}
Make() Method
The make
function will create a zeroed array and return a slice referencing an array. This is a great way to create a dynamically sized array. To create a slice using the make
function, we need to specify three arguments: type, length, and capacity.
package main
import "fmt"
func main() {
slice := make([]string, 3, 5)
fmt.Println("Length", len(slice))
fmt.Println("Capacity", cap(slice))
fmt.Println(slice)
}
Frequently Asked Questions
1. How do you create an empty slice in Go?
Answer: Use []datatype{}
to create an empty slice.
package main
import "fmt"
func main() {
myslice := []int{}
fmt.Println("Empty Slice:", myslice) // []
}
2. How do you create a slice with initial values?
Answer: Use []datatype{values}
.
package main
import "fmt"
func main() {
myslice := []int{1, 2, 3}
fmt.Println("Slice with Values:", myslice) // [1 2 3]
}
3. How do you create a slice from an array?
Answer: Use slicing syntax array[start:end]
.
package main
import "fmt"
func main() {
arr := [5]int{1, 2, 3, 4, 5}
myslice := arr[1:4]
fmt.Println("Slice from Array:", myslice) // [2 3 4]
}
4. How do you use the make
function to create a slice?
Answer: Use make(type, length, capacity)
.
package main
import "fmt"
func main() {
myslice := make([]int, 3, 5)
fmt.Println("Slice with Make:", myslice) // [0 0 0]
}
5. How do you append elements to a slice?
Answer: Use the append
function.
package main
import "fmt"
func main() {
myslice := []int{1, 2, 3}
myslice = append(myslice, 4, 5)
fmt.Println("Appended Slice:", myslice) // [1 2 3 4 5]
}
6. How do you copy one slice to another?
Answer: Use the copy
function.
package main
import "fmt"
func main() {
src := []int{1, 2, 3}
dest := make([]int, len(src))
copy(dest, src)
fmt.Println("Copied Slice:", dest) // [1 2 3]
}
7. How do you find the length and capacity of a slice?
Answer: Use len(slice)
and cap(slice)
.
package main
import "fmt"
func main() {
myslice := []int{1, 2, 3}
fmt.Println("Length:", len(myslice)) // 3
fmt.Println("Capacity:", cap(myslice)) // 3
}
8. How do you create a multidimensional slice?
Answer: Use slices of slices.
package main
import "fmt"
func main() {
matrix := [][]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
fmt.Println("Multidimensional Slice:", matrix)
}
9. How do you remove an element from a slice?
Answer: Use slicing to exclude the element.
package main
import "fmt"
func main() {
myslice := []int{1, 2, 3, 4, 5}
myslice = append(myslice[:2], myslice[3:]...)
fmt.Println("Slice after Removal:", myslice) // [1 2 4 5]
}
10. How do you iterate over a slice in Go?
Answer: Use a for
loop or range
.
package main
import "fmt"
func main() {
myslice := []int{1, 2, 3}
for i, v := range myslice {
fmt.Printf("Index: %d, Value: %d\n", i, v)
}
}
⚡ Array vs Slice
Feature | Array | Slice |
---|---|---|
Size | Fixed | Dynamic (can grow/shrink) |
Type | Value type | Reference type |
Memory | All data copied on assignment | Just the slice descriptor copied (shallow copy) |
Creation | var a [5]int | var s []int or slicing an array |
Common Usage | Rare (low-level memory control) | Very common |
Performance | No hidden cost | Some overhead with dynamic growth |
[Author: @mdimamhosen Date: 2025-04-19 Category: interview-qa/strings Tags: [go, strings, operations]]
GoLang Strings
This document provides an overview of string operations in GoLang with examples.
Frequently Asked Questions
1. How do you concatenate strings in Go?
You can concatenate strings using the +
operator.
fmt.Println("Hello, " + "World!")
2. How do you find the length of a string in Go?
Use the len
function to get the length of a string.
message := "Hello World!"
fmt.Println("Length:", len(message))
3. How do you extract a substring in Go?
Use slice notation to extract substrings.
message := "Hello World!"
fmt.Println("Substring:", message[0:5]) // "Hello"
4. How do you compare two strings in Go?
You can use ==
and !=
operators or the strings.Compare
function.
msg1 := "one"
msg2 := "two"
fmt.Println("Equal?", msg1 == msg2)
fmt.Println("Not Equal?", msg1 != msg2)
fmt.Println(strings.Compare(msg1, msg2))
5. How do you check if a string contains a substring?
Use the strings.Contains
function.
message := "Hello World!"
fmt.Println(strings.Contains(message, "World")) // true
6. How do you convert a string to uppercase or lowercase?
Use strings.ToUpper
and strings.ToLower
functions.
message := "Hello World!"
fmt.Println(strings.ToUpper(message)) // "HELLO WORLD!"
fmt.Println(strings.ToLower(message)) // "hello world!"
7. How do you split a string into substrings?
Use the strings.Split
function.
message := "Hello World!"
fmt.Println(strings.Split(message, " ")) // ["Hello", "World!"]
8. How do you replace a substring in a string?
Use the strings.Replace
function.
message := "Hello World!"
fmt.Println(strings.Replace(message, "World", "Go", 1)) // "Hello Go!"
9. How do you trim spaces from a string?
Use the strings.TrimSpace
function.
message := " Hello World! "
fmt.Println(strings.TrimSpace(message)) // "Hello World!"
10. How do you get the first character of a string?
Use indexing to access the first character.
message := "Hello World!"
fmt.Printf("First character: %c\n", message[0])
Basic String Operations
Concatenation
You can concatenate strings using the +
operator.
fmt.Println("Hello, " + "World!")
Formatting Strings
Go provides several ways to format strings using fmt.Printf
.
message := "Hello World!"
fmt.Printf("Data: %v\n", message)
fmt.Printf("Data: %+v\n", message)
fmt.Printf("Data: %#v\n", message)
fmt.Printf("Data: %T\n", message)
fmt.Printf("Data: %q\n", message)
fmt.Printf("First character: %c\n", message[0])
String Length
You can get the length of a string using the len
function.
fmt.Println("Length:", len(message))
Substrings
You can extract substrings using slice notation.
fmt.Println("Substring:", message[0:5]) // this will print "Hello"
String Comparison
You can compare strings using ==
and !=
operators or the strings.Compare
function.
msg1 := "one"
msg2 := "two"
fmt.Println("Equal?", msg1 == msg2)
fmt.Println("Not Equal?", msg1 != msg2)
fmt.Println(strings.Compare(msg1, msg2))
Additional String Functions
Contains
Check if a string contains a substring.
fmt.Println(strings.Contains(message, "World")) // true
ToUpper and ToLower
Convert strings to upper or lower case.
fmt.Println(strings.ToUpper(message)) // "HELLO WORLD!"
fmt.Println(strings.ToLower(message)) // "hello world!"
Split
Split a string into a slice of substrings.
fmt.Println(strings.Split(message, " ")) // ["Hello", "World!"]
Replace
Replace occurrences of a substring.
fmt.Println(strings.Replace(message, "World", "Go", 1)) // "Hello Go!"
Trim
Trim leading and trailing spaces.
fmt.Println(strings.TrimSpace(" Hello World! ")) // "Hello World!"
Refer to the Go documentation for more string functions and detailed usage.
[Author: @mdimamhosen Date: 2025-04-19 Category: e.g., interview-qa/topic_name Tags: [go, concurrency, channels] ]
Structs (Structures)
A struct is used to create a collection of members of different data types, into a single variable.
package main
import ("fmt")
type Person struct {
name string
age int
job string
salary int
}
func main() {
var userOne Person
userOne.name = "HuXn"
userOne.age = 18
userOne.job = "Programmer"
userOne.salary = 40000
fmt.Println(userOne)
fmt.Println("My name is", userOne.name, "I'm", userOne.age, "Years old", "My Profession is", userOne.job, "My salary is", userOne.salary)
}
Frequently Asked Questions (FAQ)
1. What is a struct in Go?
Answer: A struct is a composite data type in Go that groups together variables under a single name. These variables can be of different types.
Example:
type Person struct {
name string
age int
}
func main() {
p := Person{name: "Alice", age: 30}
fmt.Println(p)
}
2. How do you define and initialize a struct in Go?
Answer: You can define a struct using the type
keyword and initialize it using a struct literal.
Example:
type Car struct {
brand string
year int
}
func main() {
c := Car{brand: "Toyota", year: 2020}
fmt.Println(c)
}
3. Can you create an anonymous struct in Go?
Answer: Yes, you can create an anonymous struct without defining a named type.
Example:
func main() {
person := struct {
name string
age int
}{
name: "John",
age: 25,
}
fmt.Println(person)
}
4. How do you access and modify struct fields in Go?
Answer: You can access and modify struct fields using the dot .
operator.
Example:
type Book struct {
title string
author string
}
func main() {
b := Book{title: "Go Programming", author: "John Doe"}
b.title = "Advanced Go Programming"
fmt.Println(b)
}
5. Can structs have methods in Go?
Answer: Yes, you can define methods for structs.
Example:
type Rectangle struct {
width, height float64
}
func (r Rectangle) Area() float64 {
return r.width * r.height
}
func main() {
rect := Rectangle{width: 10, height: 5}
fmt.Println("Area:", rect.Area())
}
6. What is the difference between value and pointer receivers in struct methods?
Answer: Value receivers operate on a copy of the struct, while pointer receivers operate on the original struct.
Example:
type Counter struct {
count int
}
func (c *Counter) Increment() {
c.count++
}
func main() {
c := Counter{}
c.Increment()
fmt.Println(c.count)
}
7. Can structs embed other structs in Go?
Answer: Yes, Go supports struct embedding for composition.
Example:
type Address struct {
city, state string
}
type Person struct {
name string
address Address
}
func main() {
p := Person{name: "Alice", address: Address{city: "New York", state: "NY"}}
fmt.Println(p)
}
8. How do you compare two structs in Go?
Answer: You can compare structs using the ==
operator if all fields are comparable.
Example:
type Point struct {
x, y int
}
func main() {
p1 := Point{x: 1, y: 2}
p2 := Point{x: 1, y: 2}
fmt.Println(p1 == p2) // true
}
9. Can you use structs as map keys in Go?
Answer: Yes, structs can be used as map keys if all their fields are comparable.
Example:
type Point struct {
x, y int
}
func main() {
m := make(map[Point]string)
m[Point{x: 1, y: 2}] = "A Point"
fmt.Println(m)
}
10. How do you iterate over struct fields in Go?
Answer: You can use the reflect
package to iterate over struct fields.
Example:
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int
}
func main() {
p := Person{Name: "Alice", Age: 30}
v := reflect.ValueOf(p)
for i := 0; i < v.NumField(); i++ {
fmt.Println(v.Type().Field(i).Name, v.Field(i))
}
}
[Author: @mdimamhosen Date: 2025-04-19 Category: e.g., interview-qa/topic_name Tags: [go, concurrency, channels] ]
The switch Statement
The switch statement allows us to execute one code block among many alternatives.
package main
import ("fmt")
func main() {
day := 8
switch day {
case 1:
fmt.Println("Monday")
case 2:
fmt.Println("Tuesday")
case 3:
fmt.Println("Wednesday")
case 4:
fmt.Println("Thursday")
case 5:
fmt.Println("Friday")
case 6:
fmt.Println("Saturday")
case 7:
fmt.Println("Sunday")
default:
fmt.Println("Not a weekday")
}
}
Frequently Asked Questions
1. What is a switch
statement in Go?
Answer: A switch
statement is used to select one of many code blocks to execute. It is an alternative to using multiple if-else
statements.
Example:
package main
import "fmt"
func main() {
num := 2
switch num {
case 1:
fmt.Println("One")
case 2:
fmt.Println("Two")
case 3:
fmt.Println("Three")
default:
fmt.Println("Other number")
}
}
2. Can we use multiple values in a single case
?
Answer: Yes, multiple values can be grouped in a single case
.
Example:
package main
import "fmt"
func main() {
char := 'a'
switch char {
case 'a', 'e', 'i', 'o', 'u':
fmt.Println("Vowel")
default:
fmt.Println("Consonant")
}
}
3. Is break
required in Go's switch
statement?
Answer: No, break
is not required as Go automatically breaks out of the switch
after executing a case
.
4. How to use fallthrough
in a switch
statement?
Answer: The fallthrough
keyword forces the execution of the next case
even if the condition does not match.
Example:
package main
import "fmt"
func main() {
num := 1
switch num {
case 1:
fmt.Println("One")
fallthrough
case 2:
fmt.Println("Two")
default:
fmt.Println("Default")
}
}
5. Can switch
work without an expression?
Answer: Yes, a switch
can work without an expression, making it similar to a series of if-else
statements.
Example:
package main
import "fmt"
func main() {
num := 10
switch {
case num < 0:
fmt.Println("Negative")
case num == 0:
fmt.Println("Zero")
case num > 0:
fmt.Println("Positive")
}
}
6. Can we use a switch
statement with strings?
Answer: Yes, switch
can be used with strings.
Example:
package main
import "fmt"
func main() {
color := "red"
switch color {
case "red":
fmt.Println("Stop")
case "yellow":
fmt.Println("Caution")
case "green":
fmt.Println("Go")
default:
fmt.Println("Unknown color")
}
}
7. Can switch
handle type assertions?
Answer: Yes, switch
can be used to handle type assertions.
Example:
package main
import "fmt"
func main() {
var x interface{} = 42
switch v := x.(type) {
case int:
fmt.Printf("%d is an int\n", v)
case string:
fmt.Printf("%s is a string\n", v)
default:
fmt.Println("Unknown type")
}
}
8. Can switch
be used with functions?
Answer: Yes, you can use a function's return value in a switch
statement.
Example:
package main
import "fmt"
func getNumber() int {
return 3
}
func main() {
switch getNumber() {
case 1:
fmt.Println("One")
case 2:
fmt.Println("Two")
case 3:
fmt.Println("Three")
default:
fmt.Println("Other number")
}
}
9. Can switch
be nested?
Answer: Yes, switch
statements can be nested.
Example:
package main
import "fmt"
func main() {
num := 2
switch num {
case 1:
fmt.Println("One")
case 2:
fmt.Println("Two")
switch num {
case 2:
fmt.Println("Nested switch")
}
default:
fmt.Println("Other number")
}
}
10. What happens if no case
matches and there is no default
?
Answer: If no case
matches and there is no default
, the switch
statement does nothing.
Example:
package main
import "fmt"
func main() {
num := 5
switch num {
case 1:
fmt.Println("One")
case 2:
fmt.Println("Two")
}
// No output
}
[Author: @mdimamhosen Date: 2025-04-19 Category: e.g., interview-qa/topic_name Tags: [go, concurrency, channels] ]
Variables are containers for storing data values
In Go, there are two ways to declare a variable
1. Use the var keyword, followed by variable name and type
package main
import ("fmt")
var name = "John Doe" // Variable One
func main() {
var fruit = "Apple" // Variable Two
fmt.Println(name)
fmt.Println(fruit)
}
2. Use the := sign, followed by the variable value
package main
import ("fmt")
func main() {
varOne := 100
varTwo := 2
fmt.Println(varOne)
fmt.Println(varTwo)
}
Frequently Asked Questions (FAQs)
1. How do you declare a constant variable in Go?
Answer: Use the const
keyword to declare a constant variable. Constants cannot be changed after they are declared.
package main
import ("fmt")
func main() {
const pi = 3.14
fmt.Println(pi)
}
2. Can you declare multiple variables in a single line?
Answer: Yes, you can declare multiple variables in a single line using the var
keyword or :=
syntax.
package main
import ("fmt")
func main() {
var x, y, z int = 1, 2, 3
fmt.Println(x, y, z)
}
3. What is the zero value of a variable in Go?
Answer: Variables in Go are automatically assigned a zero value if not explicitly initialized.
package main
import ("fmt")
func main() {
var number int
fmt.Println(number) // Output: 0
}
4. How do you declare a global variable in Go?
Answer: Declare the variable outside of any function.
package main
import ("fmt")
var globalVar = "I am global"
func main() {
fmt.Println(globalVar)
}
5. Can you reassign a value to a variable declared with var
?
Answer: Yes, variables declared with var
can be reassigned.
package main
import ("fmt")
func main() {
var name = "John"
name = "Doe"
fmt.Println(name)
}
6. What happens if you declare a variable but do not use it?
Answer: Go does not allow unused variables and will throw a compile-time error.
package main
func main() {
var unusedVar = 10 // This will cause an error
}
7. How do you declare a variable with a specific type?
Answer: Use the var
keyword followed by the type.
package main
import ("fmt")
func main() {
var age int = 25
fmt.Println(age)
}
8. Can you declare a variable without initializing it?
Answer: Yes, but it will have a zero value.
package main
import ("fmt")
func main() {
var name string
fmt.Println(name) // Output: ""
}
9. How do you declare a variable in a block?
Answer: Use the var
keyword inside a block.
package main
import ("fmt")
func main() {
var (
x int = 10
y string = "Hello"
)
fmt.Println(x, y)
}
10. What is the difference between var
and :=
?
Answer: var
can be used globally and allows explicit type declaration, while :=
is shorthand for local variable declaration and type inference.
package main
import ("fmt")
func main() {
var name string = "John" // Explicit type
age := 30 // Type inferred
fmt.Println(name, age)
}
[Author: @mdimamhosen Date: 2025-04-22 Category: interview-qa/Variadic Tags: [go, Variadic Function] ]
Variadic Functions in Go
A variadic function in Go is a function that can accept a variable number of arguments. You define a variadic function by placing ...
before the type in the function signature, which allows the function to accept multiple arguments of that type.
Example Code: Variadic Function
package main
func print(number ...int) { // Variadic function to print numbers
for _, n := range number {
println(n) // Printing each number
}
}
func main() {
print(1, 2, 3, 4, 5) // Calling the variadic function with multiple arguments
print(1, 2) // Calling the variadic function with fewer arguments
print(1) // Calling the variadic function with a single argument
print() // Calling the variadic function with no arguments
}
Explanation:
print(number ...int)
is a variadic function, meaning it can accept any number ofint
values.- In the
main()
function, different sets of arguments are passed toprint()
:- A set of 5 integers
- A set of 2 integers
- A single integer
- No arguments at all
More Explanation on Variadic Functions:
- A variadic function works by collecting all the arguments passed into a slice.
- You can pass a slice directly to a variadic function using
...
, which unpacks the slice into individual arguments.
Example: Passing a Slice to a Variadic Function
package main
func print(numbers ...int) {
for _, n := range numbers {
println(n)
}
}
func main() {
nums := []int{10, 20, 30}
print(nums...) // Unpacking a slice and passing to the variadic function
}
Interview Questions and Answers
1. What is the advantage of using variadic functions in Go?
Answer: Variadic functions allow for flexibility in function calls, enabling you to pass a varying number of arguments without needing to overload the function. This helps avoid writing multiple versions of the same function that differ only by the number of arguments they take.
2. Can a variadic function accept multiple types of arguments?
Answer:
No, a variadic function in Go accepts only one type of argument. However, you can work around this limitation by using an interface{}
type, which allows for any type, but you will lose type safety.
Code Example:
package main
import "fmt"
func printAnything(values ...interface{}) {
for _, v := range values {
fmt.Println(v)
}
}
func main() {
printAnything(1, "Hello", 3.14, true) // Accepting multiple types
}
3. Can you have multiple variadic parameters in a function?
Answer: No, Go only allows one variadic parameter in a function. You cannot have more than one variadic parameter in the function signature.
4. How do you handle a variadic function when no arguments are passed?
Answer: If no arguments are passed to a variadic function, the parameter inside the function will be an empty slice. This allows the function to still handle the case where no arguments are provided gracefully.
Code Example:
package main
func print(numbers ...int) {
if len(numbers) == 0 {
println("No numbers provided")
return
}
for _, n := range numbers {
println(n)
}
}
func main() {
print() // No arguments provided
}
5. Can you pass a slice to a variadic function?
Answer:
Yes, you can pass a slice to a variadic function by using the ...
syntax to unpack the slice.
Code Example:
package main
func print(numbers ...int) {
for _, n := range numbers {
println(n)
}
}
func main() {
nums := []int{10, 20, 30}
print(nums...) // Passing a slice to a variadic function
}
This method unpacks the slice nums
and passes its elements individually to the print
function.
📚 Resources
This chapter contains curated coding problems and learning materials collected from various competitive programming and interview preparation platforms.
📌 Contents
-
Codeforces (CF)
A collection of selected problems categorized by difficulty and topic. -
LeetCode
Popular coding interview questions organized by data structures and algorithms. -
Other Platforms
(Optional: Add links or folders for HackerRank, AtCoder, etc., if available.)
✨ Platforms Included
Platform | Link to Website |
---|---|
Codeforces | https://codeforces.com/ |
LeetCode | https://leetcode.com/ |
📈 Goal
- Improve problem-solving skills
- Prepare for coding interviews
- Strengthen algorithmic thinking
[Author: @mdimamhosen Date: 2025-04-20 Category: e.g., link-resouces/problems Tags: [go, problem solving, cf] ]
Problem 313 - A
Problem Link
Problem 1676 - B
Problem Link
[Author: @mdimamhosen Date: 2025-04-23 Category: e.g., link-resouces/problems Tags: [go, problem solving, leetcode] ]
Problem Link:
🚀 A Journey Through Memory: The Tale of Global Variables
আজ আমরা একটা fascinating journey এ যাব - আপনার C program এর global variable গুলো কিভাবে memory তে তাদের ঘর খুঁজে নেয়। এটা একটা adventure story যেখানে আমাদের heroes হলো different types of global variables।
🎭 Meet Our Characters
আমাদের story তে তিনজন main character আছে:
const int MAX_USERS = 1000; // 👑 Raja: Read-only hero
int current_users = 0; // 🏠 Homeowner: Initialized hero
int user_buffer[500]; // 👻 Ghost: Uninitialized hero
প্রত্যেকের আলাদা personality, আলাদা needs, আর আলাদা destination!
🏰 The Memory Kingdom: Four Districts
Memory kingdom এ চারটা distinct district আছে, প্রত্যেকটার নিজস্ব rules এবং residents:
Memory Kingdom Map:
┌─────────────────────────────────────┐
│ 👑 .rodata District (Royal Court) │ ← Read-only constants
├─────────────────────────────────────┤
│ 🏠 .data District (Residential) │ ← Initialized globals
├─────────────────────────────────────┤
│ 👻 .bss District (Ghost Town) │ ← Uninitialized globals
└─────────────────────────────────────┘
👑 Chapter 1: Raja's Journey to .rodata District
আমাদের প্রথম hero Raja (const int MAX_USERS = 1000
) একজন nobleman। তার একটা fixed value আছে যা কখনো change হবে না।
Raja's Story:
- Personality: "আমি কখনো change হবো না! আমার value permanent!"
- Destination: .rodata section (Read-Only Data)
- Journey: Compile time এ ROM এ store হয়, runtime এ RAM এ copy হয় কিন্তু read-only থাকে
const char company_name[] = "TechCorp"; // Another royal resident
const float PI = 3.14159; // Mathematical royalty
কেন .rodata আলাদা section?
- Security: কেউ accidentally change করতে পারবে না
- Memory protection: Hardware level এ write-protected
- Optimization: Compiler জানে এগুলো কখনো change হবে না
Raja's House Rules:
// ✅ Legal - Reading is allowed
printf("Max users: %d\n", MAX_USERS);
// ❌ Illegal - Trying to modify const
// MAX_USERS = 2000; // Compiler error!
🏠 Chapter 2: Homeowner's Journey to .data District
আমাদের দ্বিতীয় hero Homeowner (int current_users = 0
) একজন responsible resident। তার একটা initial value আছে কিন্তু পরে change করতে পারে।
Homeowner's Story:
- Personality: "আমার একটা starting value আছে, কিন্তু আমি grow করতে পারি!"
- Destination: .data section
- Journey: একটা interesting dual-phase adventure
Phase 1: The Packing (Compile Time)
Executable File Suitcase:
┌──────────────────┐
│ current_users=0 │ ← Packed with initial value
│ pi=3.14159 │
│ name="Default" │
└──────────────────┘
Phase 2: The Moving (Runtime)
যখন program start হয়:
- Loader সব .data contents ROM থেকে RAM এ copy করে
- এখন RAM এ modification করা যায়
- Original ROM copy unchanged থাকে (backup এর মতো)
// Runtime এ এই changes শুধু RAM এ হয়
current_users = 50; // RAM copy modified
strcpy(name, "TechCorp"); // RAM copy modified
// কিন্তু ROM এ এখনো 0 আর "Default" আছে!
👻 Chapter 3: Ghost's Journey to .bss District
আমাদের তৃতীয় hero Ghost (int user_buffer[500]
) একজন mysterious character। তার কোনো initial value নেই, কিন্তু runtime এ জীবিত হয়ে ওঠে।
Ghost's Story:
- Personality: "আমি শুরুতে invisible, কিন্তু runtime এ powerful হয়ে উঠি!"
- Destination: .bss section (Block Started by Symbol)
- Journey: The most efficient adventure
The Invisible Phase (Compile Time):
Executable File:
┌──────────────────┐
│ .bss metadata: │
│ "Need 2KB space" │ ← শুধু size info, actual data নেই!
│ "Zero everything"│
└──────────────────┘
The Materialization (Runtime):
// Startup sequence:
// 1. Loader: "আমার 2KB RAM দরকার"
// 2. System: "নিয়ে যাও, সব zero করে দিলাম"
// 3. Ghost: "এখন আমি 500টা zero দিয়ে ready!"
user_buffer[0] = 100; // এখন Ghost জীবিত এবং কাজ করছে!
Ghost's Superpower: Space Efficiency
File Size Comparison:
int initialized_array[100000] = {1,2,3...}; // 🏠 400KB in file
int uninitialized_array[100000]; // 👻 0 bytes in file!
🗺️ The Complete Journey Map
Program Lifecycle Journey:
Compile Time: Runtime Memory:
┌─────────────────┐ ┌─────────────────┐
│ Executable File │ │ Active RAM │
├─────────────────┤ ├─────────────────┤
│ 👑 .rodata │ ─────────► │ 👑 .rodata │ (Read-only)
│ MAX_USERS=1000 │ │ MAX_USERS=1000 │
├─────────────────┤ ├─────────────────┤
│ 🏠 .data │ ─────────► │ 🏠 .data │ (Modifiable)
│ current_users=0 │ │ current_users=0 │
├─────────────────┤ ├─────────────────┤
│ 👻 .bss │ ─────────► │ 👻 .bss │ (Auto-zeroed)
│ (size only) │ │ user_buffer=0 │
└─────────────────┘ └─────────────────┘
🎯 The Moral of Our Story
Each Hero Has Their Purpose:
- 👑 Raja (.rodata): Security guard - protects important constants
- 🏠 Homeowner (.data): Flexible resident - can change but starts with values
- 👻 Ghost (.bss): Efficient minimalist - appears when needed, saves space
The Three Laws of Memory Kingdom:
- Law of Separation: "প্রত্যেক type এর variable এর আলাদা district আছে"
- Law of Efficiency: "Ghost district file এ কোনো space নেয় না"
- Law of Protection: "Royal court read-only, residential district modifiable"
🛠️ Practical Magic Spells (Commands)
আপনার program এর memory journey দেখতে চান?
# See the districts and their sizes
size your_program
# text data bss dec hex filename
# 1024 64 2000 3088 c10 your_program
# Detailed district information
objdump -h your_program | grep -E "\.(text|rodata|data|bss)"
🚀 Journey's End: Key Wisdom
এই journey থেকে আমরা শিখলাম:
- Memory kingdom এ চারটা আলাদা district আছে, প্রত্যেকের নিজস্ব purpose
- .rodata, .data, .bss are separate sections - একে অপরের মধ্যে included নয়
- Compiler intelligently decides কোন variable কোন district এ যাবে
- Runtime efficiency depends on understanding এই journey
এখন যখনই আপনি global variable declare করবেন, মনে রাখবেন - আপনি একটা character এর journey শুরু করে দিচ্ছেন memory kingdom এ!
Students will keep
Documentation for the mini cards project
[Author: @mdimamhosen Date: 2025-04-23 Category: e.g., mini-projects/Quantique Tags: [go, Quantique, mini-projects] ]
🔁 Quantique - Unit Converter CLI
Quantique is a beautiful CLI-based Unit Converter written in Go.
Easily convert between popular units with a modern, stylish terminal interface using box-cli-maker
and fatih/color
.
🚀 Features
- ✅ Convert:
- Meters ⇌ Feet
- Feet ⇌ Meters
- Celsius ⇌ Fahrenheit
- Fahrenheit ⇌ Celsius
- Kilograms ⇌ Pounds
- Pounds ⇌ Kilograms
- 🎨 Elegant terminal UI with colors and box layout
- 🔁 Seamless interactive loop with graceful exit
📦 Dependencies
Make sure you have Go installed.
Initialize a Go module and install the required libraries:
go mod init quantique
go get github.com/fatih/color
go get github.com/Delta456/box-cli-maker/v2
🛠️ How to Run
go build quantique.go
./quantique.exe
📸 CLI Preview
╔════════════════════════════════════════════════════╗
║ UNIT CONVERTER ║
║ Convert Meters ⇌ Feet | Celsius ⇌ Fahrenheit ║
║ | Kilograms ⇌ Pounds ║
╚════════════════════════════════════════════════════╝
📁 File Structure
Quantique/
├── go.mod
├── go.sum
└── main.go
🤝 A Note from the Author
A small contribution to the incredible Best GoLang Community Ever
URL Shortener - Go
A simple URL shortening service built with Go and MySQL. This project allows users to generate short URLs and redirect to the original long URL using a unique key.
Features
- Generate short URLs with unique keys
- Redirect to the original URL
- MySQL integration for URL storage
- JSON-based HTTP API
- Environment variable support via
.env
file
Project Structure
UrlShortner-Go/
├── config/ # Loads MySQL connection using env vars
├── database/
│ └── mysql.go # MySQL operations for saving and retrieving URLs
├── handlers/
│ └── UrlHandler.go # HTTP handlers for shortening and redirecting
├── models/ # Request/response models
├── utils/
│ └── utils.go # Random key generation
├── .env # Environment variables
└── main.go # Entry point of the server
Installation
-
Clone the repository:
git clone https://github.com/0baydullah/UrlShortner-Go.git
-
Navigate to the project directory:
cd UrlShortner-Go
-
Set up your MySQL database and table:
CREATE DATABASE urlshortener; USE urlshortener; CREATE TABLE urls ( id INT AUTO_INCREMENT PRIMARY KEY, short_key VARCHAR(255) NOT NULL UNIQUE, original_url TEXT NOT NULL );
-
Create a
.env
file in the root directory:DB_USER=your_db_username DB_PASSWORD=your_db_password DB_HOST=localhost DB_PORT=3306 DB_NAME=urlshortener
-
Run the application:
go run main.go
Usage
Shorten a URL
Send a POST
request to /shorten
:
curl -X POST http://localhost:8081/shorten -H "Content-Type: application/json" -d '{"url": "https://example.com"}'
Response:
{
"key": "abc123",
"url": "https://example.com",
"shortUrl": "http://localhost:8081/abc123"
}
or If you want to test it you can use PostMan
too! ;-)
Here is a preview from Postman (had been hosted on a free VPS, maybe expired already)
Redirect to Original URL
Visit the shortened URL:
http://localhost:8081/abc123
This will redirect to https://example.com
.
Contributing
Contributions are welcome! Feel free to open issues or submit pull requests.
CCWC (Custom Word Count)
A Go implementation of the Unix/Linux wc
command that counts bytes, lines, words, and characters in text files.
Features
- Count bytes in a file (
-c
) - Count lines in a file (
-l
) - Count words in a file (
-w
) - Count characters in a file (
-m
) - Support for reading from both files and standard input (stdin)
- Default mode that displays line, word, and byte counts together
Installation
- Ensure you have Go installed on your system
- Navigate to the project directory:
cd /Users/rokib/Developer/go_projects/bgce-archive/mini-projects/ccwc
- Build the project:
go build -o ccwc ./cmd/ccwc
Usage
Basic Usage
./ccwc [options] [filename]
If no filename is provided, ccwc reads from standard input.
Options
-c
: Print the byte count-l
: Print the line count-w
: Print the word count-m
: Print the character count (locale-dependent)
If no options are provided, ccwc displays line count, word count, and byte count.
Examples
- Count bytes in a file:
./ccwc -c testdata/test.txt
- Count lines in a file:
./ccwc -l testdata/test.txt
- Count words in a file:
./ccwc -w testdata/test.txt
- Count characters in a file:
./ccwc -m testdata/test.txt
- Default output (lines, words, and bytes):
./ccwc testdata/test.txt
- Read from standard input:
cat testdata/test.txt | ./ccwc -m
Project Structure
mini-projects/ccwc/
├── cmd/
│ └── ccwc/
│ └── main.go # Main application entry point
├── internal/
│ └── processor/
│ └── processor.go # Core processing functions
├── testdata/ # Test files directory
│ └── test.txt
├── go.mod # Go module file
└── README.md # This file
Implementation Details
The project is organized into two main components:
-
Processor Package (
internal/processor/processor.go
):- Contains core counting functions
- Implements byte, line, word, and character counting logic
- Uses efficient buffered I/O operations
-
Main Package (
cmd/ccwc/main.go
):- Handles command-line argument parsing
- Manages file operations
- Coordinates counting operations
- Formats and displays output
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
🧩 Project: Build Your Own JSON Parser (Step 1)
Imagine JSON like Lego blocks that computers use to send and understand data. In this project, we’re learning how to read those blocks and say: “Yep, this is built correctly!” or “Nope, something’s wrong!”
⸻
🪜 Step-by-Step Guide for Step 1
🛠 Step 0: Setup
“Before we play the game, we need to set up the board.”
1. Create folders like this:
jsonparser/
├── main.go
├── lexer/
│ └── lexer.go
├── parser/
│ └── parser.go
├── tests/
│ └── step1/
│ ├── valid.json
│ └── invalid.json
2. Put this in tests/step1/valid.json
{}
3. Put this in tests/step1/invalid.json
{
⸻
🧠 Step 1: Understand What We’re Building
“We’re building a tool that checks if a JSON is okay or broken.”
We want to: • Read a file. • Break it into pieces (like Lego blocks). • Check if those pieces make a real object ({}). • Say “Valid JSON” ✅ or “Invalid JSON” ❌.
⸻
🧪 The Parts of Our Tool
1️⃣ main.go — the commander
It reads the file, sends it to the lexer, then the parser, and prints the result.
package main
import (
"fmt"
"os"
"jsonparser/lexer"
"jsonparser/parser"
)
func main() {
if len(os.Args) < 2 {
fmt.Println("Usage: ./jsonparser <path-to-json-file>")
os.Exit(1)
}
filePath := os.Args[1]
data, err := os.ReadFile(filePath)
if err != nil {
fmt.Printf("Failed to read file: %v\n", err)
os.Exit(1)
}
tokens := lexer.Tokenize(string(data))
if parser.Parse(tokens) {
fmt.Println("Valid JSON")
os.Exit(0)
} else {
fmt.Println("Invalid JSON")
os.Exit(1)
}
}
⸻
2️⃣ lexer/lexer.go — the scanner
It breaks the string like {} into tokens (chunks), like:
[LEFT_BRACE, RIGHT_BRACE]
package lexer
import "strings"
type TokenType string
const (
LEFT_BRACE TokenType = "{"
RIGHT_BRACE TokenType = "}"
ILLEGAL TokenType = "ILLEGAL"
EOF TokenType = "EOF"
)
type Token struct {
Type TokenType
Literal string
}
func Tokenize(input string) []Token {
var tokens []Token
input = strings.TrimSpace(input)
for _, ch := range input {
switch ch {
case '{':
tokens = append(tokens, Token{Type: LEFT_BRACE, Literal: "{"})
case '}':
tokens = append(tokens, Token{Type: RIGHT_BRACE, Literal: "}"})
default:
// not a valid character in step 1
tokens = append(tokens, Token{Type: ILLEGAL, Literal: string(ch)})
}
}
tokens = append(tokens, Token{Type: EOF, Literal: ""})
return tokens
}
⸻
3️⃣ parser/parser.go — the judge
It looks at the tokens and decides if it’s correct.
package parser
import "jsonparser/lexer"
func Parse(tokens []lexer.Token) bool {
// Step 1: Only valid thing is [LEFT_BRACE, RIGHT_BRACE, EOF]
if len(tokens) != 3 {
return false
}
return tokens[0].Type == lexer.LEFT_BRACE &&
tokens[1].Type == lexer.RIGHT_BRACE &&
tokens[2].Type == lexer.EOF
}
⸻
▶️ Run It!
Go into your terminal and run this:
go run main.go tests/step1/valid.json # ✅ Should print: Valid JSON
go run main.go tests/step1/invalid.json # ❌ Should print: Invalid JSON
⸻
🎓 What Did We Learn? • ✅ JSON is just a way to store data, like a toy box. • ✅ Lexers break it into tokens (like sorting toys). • ✅ Parsers check if the toys are arranged correctly. • ✅ We only accept {} right now. • ❌ Anything else is “broken” JSON.
⸻
🧠 Coming Next…
In Step 2, we’ll look inside the box and check for strings like:
{"key": "value"}
⸻
🐳 Go Debugging Playground – Docker-এর মাধ্যমে ইন্টার্যাকটিভ GDB
এই Docker ইমেজটি দিয়ে তুমি খুব সহজেই Go প্রোগ্রাম কম্পাইল এবং gdb
দিয়ে স্টেপ-বাই-স্টেপ ডিবাগ করতে পারবে।
🚀 শুরু করার নিয়ম
১. Docker Hub থেকে ইমেজ ডাউনলোড করো:
docker pull jsiqbal/go-debug-ready
২. কন্টেইনার রান করাও:
docker run -it --name go-debug jsiqbal/go-debug-ready
🧠 কন্টেইনারের ভিতরে যা করতে হবে
কন্টেইনারে ঢুকে এই ধাপগুলো অনুসরণ করো:
৩. Go প্রোগ্রামের ফোল্ডারে যাও:
cd /app
৪. কোড দেখো বা এডিট করো:
nano add.go
কোডটা দেখতে এরকম:
package main
import "fmt"
func add(a, b int) int {
return a + b
}
func main() {
result := add(3, 5)
fmt.Println("Result:", result)
}
৫. Go বাইনারি ডিবাগিং ইনফো সহ বানাও:
go build -gcflags="all=-N -l" -o add add.go
🛠️ ব্যাখ্যা:
-N
: অপটিমাইজেশন বন্ধ-l
: ইনলাইনের মত টেকনিক বন্ধ
৬. GDB চালাও এবং ডিবাগ শুরু করো:
gdb ./add
GDB চালু হলে লিখো:
break main.main # main ফাংশনে ব্রেকপয়েন্ট দাও
run # প্রোগ্রাম চালাও
n # পরের লাইনে যাও
info locals # লোকাল ভেরিয়েবলগুলো দেখো
info registers # CPU রেজিস্টারগুলো দেখো
x/1i $pc # বর্তমান ইনস্ট্রাকশনটা কী দেখো
🔁 আবার চালু করতে চাইলে:
docker start -ai go-debug
না চাইলে পুরো নতুন করে চালাও:
docker rm -f go-debug
docker run -it --name go-debug jsiqbal/go-debug-ready
Todo CLI
A simple command-line interface (CLI) application for managing your to-do tasks, built with Go.
Features
- Add new tasks
- List all tasks (with --all flag for completed tasks)
- Mark tasks as completed
- Delete tasks
Project Structure
todo-cli/
├── cmd/
│ └── tasks/
│ └── main.go
└── internal/
└── task/
├── task.go
└── storage.go
Installation
- Clone the repository:
git clone https://github.com/OxRokib/bgce-archive.git
- Navigate to the project directory:
cd bgce-archive/mini-projects/todo-cli
- Build the application:
go build -o todo cmd/tasks/main.go
Usage
Add a Task
./todo add "Your task description"
List Tasks
List incomplete tasks:
./todo list
List all tasks (including completed):
./todo list --all
Mark a Task as Completed
./todo complete <task-id>
Delete a Task
./todo delete <task-id>
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
🧠 কম্পিটিটিভ প্রোগ্রামিং গাইড (CP Guide in Bengali)
📘 এই গাইডটি তৈরি করা হয়েছে বাংলায় CP শেখার সুবিধার্থে। টেকনিক্যাল টার্ম এবং কোড ইংরেজিতে রাখা হয়েছে যাতে ইন্টারন্যাশনাল স্ট্যান্ডার্ড ফলো করা যায়।
📅 Discord session content
সেশন | তারিখ | আলোচনা করা টপিকস | Instructor (Discord name) |
---|---|---|---|
সেশন ১ | ২০২৫-০৫-০৫ | 1. প্রবলেম সলভিং আর CP-এর ফিলোসফি 2. কেন আমরা CP করবো? 3. The Right Problem Solving Mindset 4. Exercise vs Problem | popcycle |
সেশন ২ | ২০২৫-০৫-০৭ | 1. Problem Solving mindset ঠিক করার দারুন কিছু উপায় 2. Strategy, tactics আর pattern চিনে নেওয়ার কৌশল 3. Mindset আর knowledge—দুটোরই importance 4. Basic math ভিত্তিক problem 5. Census-taker problem ও তার solution 6. কীভাবে একটা solid math foundation তৈরি করবেন | popcycle |
সেশন ৩ | ২০২৫-০৫-১২ | 1. কিছু Golang conceptual exercise 2. Basic Math problems in CP → GCD, LCM, Prime check, Divisor, Modulo math, Factorial 3. Live coding এবং Q&A session | popcycle |
সেশন ৪ | ২০২৫-০৫-১৫ | 1. Nebula Clash 001 contest এর প্রব্লেম নিয়ে বিস্তারিত আলোচনা এবং upsolving 2. Problem Solving এর পিছনের idea, fastIO, concept এবং কিভাবে একটি problem approach করতে হয় 3. Problem solving এর জন্য সাধারণ কিছু math এবং algorithm | nayemul_islam |
সেশন ৫ | ২০২৫-০৫-১৭ | 1. Complexity জিনিসটা আসলে কি? 2. দুই ধরণের complexity : time complexity এবং memory complexity 3. কেন complexity সম্পর্কে ধারণা থাকটা important 4. CP তে complexity কীভাবে কাজে লাগে 5. কীভাবে complexity সম্পর্কে জানার মাধ্যমে আমরা একটি algorithm কতটুকু efficient সে সম্পর্কে ধারণা পেতে পারি 6. complexity প্রকাশ করার বিভিন্ন Notation (যেমন Big O, Big omega, Big theta) 7. কীভাবে Notation গুলো কাজ করে এবং কীভাবে এই notation গুলোর মাধ্যমে complexity হিসেব করা যায়? 8. Big O calculate করার বিভিন্ন rules 9. বিভিন্ন ধরণের time complexity (O(1), O(logn), O(n), O(nlogn), O(n^2) ইত্যাদি) 10. বিভিন্ন ধরণের memory complexity 11. Recursive function, nested loop, array declaration এর complexity | MArhamAA |
সেশন ৬ | ২০২৫-০৫-১৯ | 1. Golang এ normal input এবং output method 2. bufio এবং os এর মাধ্যমে I/O handling3. .txt file এবং অন্যান্য text file থেকে input এবং output handle করা4. FastIO কি? buffered IO কেন fast? 5. buffer কি? buffered IO কীভাবে ভিতরে ভিতরে কাজ করে? 6. Buffered I/O vs unbuffered I/O 7. Buffered I/O inside Internal Memory 8. CP তে fastIO কেন necessary? | popcycle |
সেশন ৭ | ২০২৫-০৫-২১ | 1. BruteForce কি এবং কেন BruteForce দরকার? 2. প্রত্যেকটা problem কি BruteForce দিয়ে solve করা উচিত? 3. BruteForce নিয়ে কি প্রথমেই ভাবা উচিত? কেন? 4. বিভিন্ন ধরণের problem BruteForce দিয়ে solve করার উদাহরণ | MArhamAA |
সেশন ৮ | ২০২৫-০৫-২৪ | 1. FastIO in Golang part 2 2. FastIO template of Golang for CP 3. defer function এবং এটি কী করে?4. Buffered I/O flush করার ক্ষেত্রে defer কীভাবে কাজ করে | popcycle |
সেশন ৯ | ২০২৫-০৫-২৬ | 1. Greedy technique আসলে কী? 2. আমাদের এটা কেন দরকার? brute force কি যথেষ্ট না? 3. বাস্তব problem-এ greedy technique দিয়ে কীভাবে approach করতে হয় 4. প্রথমে brute force চিন্তা করা → এরপর কীভাবে greedy দিয়ে optimize করা যায় | toji |
সেশন ১০ | ২০২৫-০৫-২৮ | 1. Post contest আলোচনা 2. NC002 Problems Uplsolving 3. Q&A related to contest | MArhamAA, popcycle |
সেশন ১১ | ২০২৫-০৬-০১ | 1. Linear search কী এবং naming convention-এর ব্যাপারটা 2. Binary search: এর implementation, complexity, এবং বিভিন্ন use case 3. Binary search ভিত্তিক practice problems | toji |
সেশন ১২ | ২০২৫-০৬-০২ | 1. Binary search part 2 2. Lower bound এবং Upper bound concepts 3. Binary Search on Answer technique 4. Floating point number এর উপর binary search 5. Binary search ভিত্তিক আরও কিছু practice problems | MArhamAA |
💡 নতুন সেশন যুক্ত হতে থাকবে সময় অনুযায়ী।
Exercises to Practice with Golang
-
প্রিন্ট করুন:
"Hello World"
- দুটি সংখ্যার যোগফল বের করুন
- If-Else দিয়ে Even/Odd চেক
- Loop দিয়ে ১ থেকে N পর্যন্ত প্রিন্ট করুন
- Function ব্যবহার করে দুই সংখ্যার গড় বের করুন
- Vowel or Consonant (dncpc1)
- Restricted (dncpc2)
- Fitness (dncpc2)
- Programming Education (dncpc5)
পরবর্তীতে আরও
exercise
add করা হবে।
Problem list
Basic Mathematical problems
- Timus 1000
- Timus 1409
- Project Euler 1
- Children and Candies (dncpc1)
- Cloudberry Jams (dncpc1)
- Restuarant (dncpc1)
- Hashmat the Brave warrior
- Between two integers (dncpc2)
- Domino Piling (dncpc2)
- Easy problem (dncpc3)
- Election go brrr (dncpc3)
- A game of choice (dncpc3)
- Sandglass (dncpc3)
- Multiple of 2 and N (dncpc4)
- Atocoder Crackers (dncpc4)
- Soldier and Bananas (dncpc4)
- Vasya and Socks (dncpc4)
- Garden (dncpc5)
- Clock Conversion (dncpc5)
- Plus Minus X (dncpc6)
Beginner Friendly CP problems
- Weird Algorithm
- Concatenation of Array
- Sakurako's Exam
- Fifty-Fifty (dncpc6)
- Good Kid (dncpc6)
- Make it Big (dncpc6)
- Three Doors (dncpc6)
🧩 Problems made by the community
Problem Code | Problem Name & Link | Author(Discord name) |
---|---|---|
2101 | সমান ভাগের রহস্য | popcycle |
2102 | চেস বোর্ডের সংকেত | popcycle |
2103 | একই হিরে দু’বার! | popcycle |
2201 | BGCE CP sessions | popcycle |
2202 | Tai Lung’s Trial of Balance | popcycle |
2203 | An Easy Problem : Revisited to Combination | toji |
2204 | Challenge to Kraken | toji |
2205 | Divisible Positive Subset | MArhamAA |
2206 | Yet Another LCS Problem | MArhamAA |
পরবর্তীতে আরও প্রব্লেম এবং ক্যাটাগরি যুক্ত করা হবে।
📘 Tips & Resources
Important লিংকস আর রিসোর্স:
- 📚 Competitive Programming Handbook - CSES
- 🌐 CP Algorithms
- 📊 Big-O Cheat Sheet
- 🧪 CS50x Problem Sets
- 👀 Blind 75
- Fast I/O template for Golang
- DSA Series by Shradha Ma'am
আস্তে আস্তে আরও resources যুক্ত করা হবে।
আমাদের যত previous contest
No. | Contest type | Contest link |
---|---|---|
1. | Daily | dncpc1 |
2. | Daily | dncpc2 |
3. | Daily | dncpc3 |
4. | Weekly | NC001 |
5. | Daily | dncpc4 |
6. | Daily | dncpc5 |
7. | Daily | dncpc6 |
8. | Weekly | NC002 |
কিভাবে এই guide ব্যাবহার করবেন
- প্রতিদিন discord এ দেওয়া exercises/problems গুলো solve করবেন।
- নিয়মিত আমাদের session এবং contest গুলোতে participate করুন।
- সেশন লিস্ট নিয়মিত আপডেট করুন।
- বেশি problem solve করা উদ্দেশ্য নয়, বরং ভালোভাবে বুঝে problem solving করবেন।
- নিজের একটি github repo তৈরি করুন এবং এই guide এর problem solution গুলো সেখানে add করতে পারেন।
এই গাইডের সাথে থাকুন, নিজের প্রগ্রেস ট্র্যাক করুন, আর শেখা চালিয়ে যান!
Events (full term)
- dncpc = Daily (Nebula-Clash) practice contest
- NC = Nebula Clash
[Author: @ifrunruhin12 Date: 2025-05-09 Category: docs/warp ]
🛣️ CP রোডম্যাপ: Zero থেকে শুরু, হয়ে উঠুন CP গুরু
এই গাইডে আমরা যেভাবে এগোবো — এটি শুধু একটি সঠিক পথ না, বরং বাস্তবভিত্তিক ও প্রমাণিত একটি রোডম্যাপ। ধাপে ধাপে শেখা, চর্চা করা এবং নিজের স্কিল লেভেল বাড়ানোই আমাদের মূল লক্ষ্য।
1. Programming Language Basics (Go)
→ variable, data type, input/output, loop, function, scope ইত্যাদি নিয়ে হাতে-কলমে শেখা।
2. Philosophy এবং Mindset of Problem Solving
→ প্রবলেম সলভিং-এর পিছনের ভাবনা, attitude ও সফল mindset তৈরি করার কৌশল।
3. Basic Exercise using Go
→ Go দিয়ে ছোট ছোট প্র্যাকটিস প্রবলেম সমাধান করা যাতে core concepts ক্লিয়ার হয়।
4. Basic Math Problem Solving with Go
→ GCD, LCM, Prime Check, Divisor, Modulo Math, Factorial ইত্যাদি সমস্যার প্র্যাকটিস।
5. Solid Math Foundation তৈরি
→ number theory-এর দরকারি অংশ, intuition বিল্ড করা এবং ম্যাথ নিয়ে ভয় কেটে ফেলা।
6. Algorithm Introduction
→ algorithm মানে কী, কেন গুরুত্বপূর্ণ, এবং কীভাবে চিন্তা করে algorithm ডিজাইন করবেন।
7. Data Structure Basic Operations (Read, Search, Add) using Go
→ array, slice, map এর উপর কাজ করা এবং basic operation বুঝে নেওয়া।
8. Time Complexity এবং Big O Notation Explained
→ প্রবলেম সলভিং-এ efficiency বোঝা, Big O এর ধারণা তৈরি করা।
9. Array এবং Slice ভিত্তিক Algorithms
→ prefix sum, sliding window, two pointer technique এর ব্যবহার।
10. Search Algorithms
→ linear search, binary search, এবং binary search on answer।
11. Greedy Algorithms
→ কখন greedy কাজ করে, coin change, activity selection ইত্যাদি প্রবলেম।
12. Sorting Techniques
→ built-in ও custom sort: bubble, selection, insertion, merge sort, recursion এর প্রাথমিক ধারণা।
13. Recursion
→ base case, call stack, এবং recursive thinking।
14. Dynamic Programming (DP)
→ memoization এবং tabulation, classic DP প্রবলেমের মাধ্যমে concept বোঝা।
15. Introduction to Graphs
→ node, edge, BFS, DFS এবং graph traversal-এর মূল ধারণা।
16. Basic Contest Strategy
→ contest time management, কোন প্রবলেম আগে করবেন, frustration handle করার টিপস।
এই রোডম্যাপ অনুযায়ী আগালে, আপনি একদিকে যেমন প্রোগ্রামিং-এর বেসিক মজবুত করতে পারবেন, অন্যদিকে ধীরে ধীরে advanced level-এ প্রবেশ করার জন্য প্রস্তুত হবেন।
[Author: @ifrunruhin12 Date: 2025-05-09 Category: docs/warp ]