Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

🌐 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
💬 DiscordJoin the Go Community on Discord – Real-time discussions, questions, support, and collab rooms.
📘 Facebook GroupJoin the Go Facebook Community – Casual Q&As, success stories, community posts, and announcements.
🎥 YouTube ChannelSubscribe 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

MicroserviceDescriptionDocumentation 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)

PermissionDescription
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/

PermissionApplies to
curate:interview_qaCan organize, categorize, and reorder Q&A content
bulk_upload:interview_qaUpload multiple Q&As via CSV or UI
label:difficulty_levelCan assign difficulty labels (easy/med/hard)
verify:interview_qaTrusted users can verify accuracy of Q&A
suggest_edit:interview_qaSubmit Q&A revisions for approval
link:qa_to_topicLink questions across topic-wise and company-wise sections

2. class-notes/

PermissionApplies to
format:class_noteFormat content (LaTeX, markdown support)
translate:class_noteUpload alternate language versions
rate:note_qualityRate based on helpfulness/accuracy
submit_note_reviewPeer review notes
merge_notesCombine similar notes into one resource

3. project-archive/

PermissionApplies to
link:project_githubAttach GitHub repo link
mark:project_stableCertify project as stable/maintained
fork:community_projectDuplicate project into sandbox for experimentation
assign:maintainerAssign project maintainers
create:project_tagsDefine tags like "CLI", "REST", "gRPC" etc.

4. image-infographic-archive/

PermissionApplies to
upload:image_infographicUpload PNG/SVG/PDF
optimize:imageResize/compress for performance
annotate:imageAdd notes or highlight sections
group:infographicsCreate themes/sets (e.g., Goroutine Internals Set)

5. community-stories/

PermissionApplies to
submit:storySubmit a personal or experience story
moderate:storyApprove or reject stories
tag:story_categoryLabel stories (job hunt, rejections, etc.)
feature:storyHighlight on community page
approve:anonymous_storyAllow anonymous publishing

6. package-archive/

PermissionApplies to
upload:package_sourceUpload zip/tarball or Git link
verify:package_integrityEnsure no malicious code
test:packageRun CI on submitted code
mark:package_deprecatedDeprecate old packages
create:package_docWrite documentation for package

7. community-blogs/

PermissionApplies to
submit:blog_postWrite and submit a blog
edit:others_blogAllow editing of other authors' blogs (moderator only)
review:blog_postCan review before publishing
pin:blog_postPin post to top of page

8. news-events/

PermissionApplies to
submit:eventSubmit conference or event
create:event_recapSummarize events
organize:event_listingCurate future/past events
assign:event_hostAdd moderators for meetups/hackathons

9. video-archive/

PermissionApplies to
embed:video_linkAttach YouTube or local hosted video
transcribe:videoAdd subtitle or transcript
review:video_contentModerate for quality or relevance
feature:videoSpotlight video on homepage
clip:video_segmentCreate mini-clips or highlights

10. course-content/

PermissionApplies to
submit:course_moduleCreate lessons or sections
assign:course_ownerAppoint course maintainer(s)
review:course_contentApprove/reject modules
track:course_progressSee student analytics (admin only)

PermissionApplies to
submit:linkAdd blog/tool/documentation link
validate:linkCheck for broken/dead links
approve:external_resourceManual approval for outbound links
organize:bookmark_listAllow curating themed collections

✅ Bonus System Permissions

PermissionApplies to
manage:usersAdmin only — manage roles, bans, profile data
manage:rolesCreate/update roles and their permission sets
audit:logsView user activity logs
backup:dataExport platform content
toggle:maintenance_modeTake platform down for maintenance
view:analyticsSee usage and traffic reports
send:notificationsSystem-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

📌 COMMIT STRATEGY

🔧 Setup

make setup-commit-hook

Commit Message Format

[<service>] (<type/feature-name>): <Capitalized short description>

💡 Allowed Types

  • feat – New feature or functionality
  • fix – Bug fix or issue correction
  • patch – Minor updates or hotfixes
  • docs – Documentation changes
  • style – Code style changes (formatting, linting)
  • refactor – Code restructuring without behavior change
  • test – Adding or updating tests
  • chore – Build tasks, CI configs, or other maintenance

🧪 Example Commits

[inventory] (feat/add-product): Add product listing endpoint
[auth] (fix/token-expiry): Correct token expiry issue
[payment] (patch/update-paypal): Update PayPal integration
[docs] (docs/readme): Update CLI tool usage instructions

Notes for contributors:

  • Service: Use the relevant service or package name in square brackets.
  • Type/feature-name: Specify the type and concise feature name in parentheses.
  • Description: Must start with an uppercase letter and clearly state the change.

🧩 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> or fix/<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

📘 BGCE Translation Guide (Simple & Clear Bangla Style)

This is how we’ll translate stuff for the BGCE book to make sure it's beginner-friendly, chill, and clear for Bengali devs. To ensure consistency, clarity, and accessibility, follow these guidelines while translating technical content to Bengali for the BGCE book:

Retain English for Key Technical Terms

  • Always use English for programming keywords, tools, and common dev jargon.

  • Examples:

    • ✅ code (❌ কোড)

    • ✅ closure (❌ ক্লোজার)

    • ✅ visualization (❌ ভিজ্যুয়ালাইজেশন)

⚠️ Use discretion — if the English term is very commonly used in Bengali dev circles, retain it.

Prefer Natural Language Over Literal Translation

  • Avoid overly formal or uncommon Bengali words.

  • Translate meaning, not word-for-word.

  • Example:

    • ❌ "স্ট্যাক বনাম হিপ"

    • ✅ "Stack vs Heap" or "স্ট্যাক vs হিপ"

CLI and Code Blocks Must Stay in English

  • Never translate code snippets, terminal commands, or code block outputs.

  • Example:

    • ❌ git push → গিট পুশ

    • ✅ Leave git push as-is.

Don’t translate word-for-word, make it feel natural

  • Say it the way you'd explain to a friend.

  • Example:

    • English:

    "If a variable is used outside a function (like in a returned closure), it moves to the heap."

    • ✅ Good Bangla:

    “যদি কোনো ভেরিয়েবল ফাংশনের বাইরে ইউজ হয় (যেমন রিটার্ন করা কোনো ক্লোজার-এর ভিতরে), তখন সেটা হিপে চলে যায়।”

    • ❌ Bad Bangla:

    “যদি কোনো ভেরিয়েবল ফাংশনের বাইরে (যেমন একটি রিটার্ন হওয়া ক্লোজারে) ব্যবহৃত হয়, তবে সেটি হিপে স্থানান্তরিত হয়।”

Add extra words if needed cause clarity > literal

  • Sometimes adding 2–3 extra words makes things way easier to understand. Do that.

  • Example:

    • English: "Stack and Heap"

    • Bangla: “স্ট্যাক আর হিপ কীভাবে কাজ করে”

Small add-ons = big clarity

No bookish or rare Bengali words

  • Don’t use words people don’t even hear in movies or the street.

  • Instead, use how devs actually talk.

UI terms, buttons, tool names - keep original English

  • Example:

    • ✅ "Click the Run button" → keep Run in English

Markdown formatting stays same

  • Don’t break bullet points, code formatting, bold text, etc.

🎯 Goal: বাংলা হবে এমন, যেটা একজন নতুন ডেভেলপার পড়ে হাসে না বরং বুঝে। Simple, clear, and helpful. No extra drama.

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 HandleRole
@username1Lead Maintainer
@username2Domain 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 the bytebook 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 mainexecutable প্রোগ্রামের জন্য বাধ্যতামূলক
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 explicitly int টাইপের বলে দেওয়া হয়েছে।

3. Implicit Type Declaration

var a = 10
  • টাইপ উল্লেখ করা হয়নি, তবে a এর টাইপ int হিসাবে নির্ধারিত হবে ১০ দেখে।

📘 Data Types

Go ভাষায় বিভিন্ন ধরনের ডেটা টাইপ আছে, যেগুলো মূলত 3 টি ভাগে ভাগ করা যায়।

১. Numeric Types

Go-তে numeric types মূলত তিনটি ভাগে বিভক্ত থাকে।

Integer Types

TypeSizeDescription
intplatform-dependentসাধারন পূর্ণসংখ্যা
int88-bit-128 to 127
int1616-bit-32,768 to 32,767
int3232-bit-2,147,483,648 to 2,147,483,647
int6464-bit-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
uintunsigned int0 to 4,294,967,295
uint80 to 255Unsigned 8-bit integer
uint160 to 65535Unsigned 16-bit integer
uint320 to 4 billion+Unsigned 32-bit
uint64বিশাল ধনাত্মক সংখ্যাUnsigned 64-bit

Floating Point Types

TypeDescription
float3232-bit decimal
float6464-bit decimal (default)

Complex Types

TypeDescription
complex64Real + Imaginary (float32)
complex128Real + Imaginary (float64)

২. String Type

  • Represents text.
var message string = "Hello, Go!"

৩. Boolean Type

  • Holds either true or false.
var isGoFun bool = true

✅ Summary Table

CategoryExample Type
Numericint, float64
Booleanbool
Stringstring

✅ 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✅ উদাহরণসহ

[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 to main()

🔹 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.gopackage 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 AssignmentIIFE সাথে সাথে চলে; অ্যাসাইনমেন্ট পরে কল করতে হয়

[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 in add(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) { ... }

৩. 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 এর ভেতরের anonymous add ফাংশন
    • প্রয়োজনীয় মেশিন কোড + মেটাডাটার বাইনারি জেনারেট করে

বাইনারি ফাইলে থাকে:

  • কোড সেগমেন্ট: কনস্ট্যান্ট 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}

মেমোরি লেআউট

AddressValueMeaning
0x10003arr[0]
0x10046arr[1]

নোট: আসল এড্রেস এখানে কল্পনা করা হয়েছে। মূল ধারণা হলো, অ্যারের সব উপাদান মেমোরিতে একসাথে (contiguously) সংরক্ষিত থাকে।

আরেকটি উদাহরণ:

arr2 := [3]string{"I", "love", "you"}
IndexValue
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, length এবং capacity নির্ধারণ করার উপায়

নিম্নোক্ত built-in ফাংশন ব্যবহার করে Slice এর length এবং capacity বের করা যায়:

  • len(slice) ➡️ Length
  • cap(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, কিন্তু capacity cap = 5 পর্যন্ত হতে পারে reallocation এর আগ পর্যন্ত

🕳 9. Empty / Nil 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 কে দ্রুত এবং মেমরি সাশ্রয়ী করে তোলে।


🤯১৩. কিছু ইন্টারেস্টিং ইন্টারভিউ প্রশ্নের উদাহরণ

⚡ Some 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):

এরপর আসে সবচেয়ে বড় বিপ্লব – MicroprocessorIntel 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:

YearCompanyProductBitRAM (approx.)
1952IBMIBM 70136-bit8KB+
1964IBMSystem/3608/16-bit16–512KB
1976AppleApple I8-bit4KB
1977AppleApple II8-bit4–48KB
1980MicrosoftMS-DOS (for IBM PC)16-bit64–640KB
1985MicrosoftWindows 1.016-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 LabsKen ThompsonDennis Ritchie Unix তৈরি করেন।
      • 🧪 এটি C programming language ব্যবহার করে লেখা হয়, যা একে আরও বহনযোগ্য করে তোলে।
    • 📚 Unix থেকে জন্ম নেওয়া জনপ্রিয় OS:
      • Linux 🐧
      • Mac OS 🍎
      • BSD, Solaris ইত্যাদি
  • 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:

YearEvents
1990Windows 3.0 – GUI, computing experience এ ব্যাপক পরিবর্তন আনে
1995Windows 95 – Taskbar, Start Menu ও Plug-and-Play
2009Windows 7 – Enhanced features, speed, and resource usage
2012Windows 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

রেজিস্টার নামপূর্ণরূপ / বর্ণনাকাজের ধরন
SPStack Pointerstack এর Top কে point করে
BPBase PointerStack frame এর base কে point করে
IRInstruction Registerবর্তমানে execute হওয়া instruction রাখে
PCProgram Counterপরবর্তী instruction address ধরে রাখে
General Purpose Registers(যেমন AX, BX, CX, DX)Data transfer, calculation ইত্যাদিতে ব্যবহৃত

🗄️ General Purpose Registers

RegisterSizeDescriptionTypical Use
AL8-bitLower 8 bits of AXstore data during arithmetic, logic, or data transfer operations
BL8-bitLower 8 bits of BXGeneral-purpose data storage
CL8-bitLower 8 bits of CXLoop counters, shift/rotate counts
DL8-bitLower 8 bits of DXI/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-bit16-bit32-bit64-bitDescription
ALAXEAXRAXAccumulator register family
BLBXEBXRBXBase register family
CLCXECXRCXCount register family (used for loops, shifts)
DLDXEDXRDXData register family

🏛️ Register Hierarchy

Register64-bit part32-bit part16-bit part8-bit high8-bit low
RAXRAXEAXAXAHAL
RBXRBXEBXBXBHBL
RCXRCXECXCXCHCL
RDXRDXEDXDXDHDL

⚙️ 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 Segmentconst, func / instructions (যা পরিবর্তন হবে না / Read only)
  • Data Segment → global variable
  • Stack → function calls & local variable
  • Heap → 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

  1. Processing Unit

    • Arithmetic Logic Unit (ALU): সব ধরনের গাণিতিক (arithmetic) এবং যৌক্তিক (logical) operations করে থাকে।
    • Control Unit (CU): CPU এর মধ্যে গাণিতিক (arithmetic) এবং যৌক্তিক (logical) operations পরিচালনা করে, input/output এবং instruction decoding কীভাবে হবে তা কন্ট্রোল করে।
  2. 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

  1. OS executable code আনে HDD থেকে → RAM এ লোড করে
  2. OS একটি process create করে
  3. 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! 🧑‍🏫


🧱 কিভাবে কাজ করে?

  1. CPU এখন একটা প্রসেস (ধরো গেম) চালাচ্ছে।
  2. হঠাৎ OS বলে “এই তো, ভিডিও কল আসছে! আগে এটাকে চালাও।”
  3. তখন CPU গেমের অবস্থা (registers, state) একটা PCB-তে রেখে দেয়
  4. এরপর নতুন প্রসেস (ভিডিও কল) এর অবস্থা 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 RegistersCPU-তে চলা হিসাবের শেষ অবস্থান
Memory Management Infoপ্রসেস কোথায় কোথায় RAM ব্যবহার করছে
I/O Infoইনপুট-আউটপুট ডিভাইসের সাথে সম্পর্কিত তথ্য
Accounting Infoপ্রসেস কত সময় চালানো হলো, কে চালালো ইত্যাদি

🌀 উদাহরণ দিয়ে বোঝা যাক:

ধরো তুমি একটি গেম খেলছো, আর তোমার ভাই ইউটিউবে ভিডিও দেখছে।

➡️ গেমটা এক ধরনের প্রসেস, ইউটিউব আরেকটা।
➡️ অপারেটিং সিস্টেম এই দুই প্রসেসকে আলাদা করে রাখতে PCB ব্যবহার করে।

➡️ প্রতিটা গেম/ভিডিও প্রসেসের জন্য আলাদা PCB থাকে যখন তুমি গেম থেকে বের হয়ে ইউটিউবে গেলে, তখন OS:

  1. গেমের সব তথ্য PCB-তে রেখে দেয়
  2. ইউটিউবের তথ্য 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 SwitchingCPU এক প্রসেস থেকে আরেকটায় যায়
PCBপ্রতিটি প্রসেসের গুরুত্বপূর্ণ তথ্য যেখানে রাখা হয়
ConcurrencyCPU একসাথে অনেক প্রসেস চালাচ্ছে এমন একটা অভিজ্ঞতা দেয়

[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 বাড়ে

৩. তুলনামূলক পার্থক্য

বিষয়ConcurrencyParallelism
কাজের ধরনএকাধিক কাজ context switch করে execute হয়একাধিক কাজ একসাথে চলতে থাকে
প্রয়োজনীয়তাSingle-core CPU-তেও সম্ভবMulti-core CPU প্রয়োজন
বাস্তব উদাহরণYouTube অ্যাপের বিভিন্ন ফিচার একসাথে চলাVideo rendering-এ একাধিক core কাজ করে
উদ্দেশ্যঅনেক কাজকে একসাথে handle করাকাজগুলো দ্রুত এবং একযোগে শেষ করা
Task Execution StyleInterleaved (ক্রমাগত পালাক্রমে)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 🧵

FeatureProcessThread
🔒 Resource Isolationপ্রতিটি Process এর নিজস্ব memory ও resources থাকেএকই Process এর মধ্যে সব Thread একই memory ও resources শেয়ার করে
🔄 Communicationজটিল; Inter-Process Communication (IPC) mechanisms প্রয়োজন হয়সহজ; shared memory ব্যবহার করে Thread গুলো একে অপরের সাথে যোগাযোগ করে
OverheadProcess তৈরি ও পরিচালনার জন্য বেশি overhead লাগেThread তৈরি ও পরিচালনা তুলনামূলকভাবে কম overhead
⏱️ ConcurrencyConcurrency সম্ভব, তবে 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 থাকে। নিচে এ সম্পর্কে বিস্তারিত দেওয়া হল:

TypeSizeRange
int88 bit / 1 byte-128 to 127
int1616 bit / 2 bytes-32,768 to 32,767
int3232 bit / 4 bytes-2,147,483,648 to 2,147,483,647
int6464 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

Bits31 ... 8 (Unused/Padding)76543210
Bit Values00000000 00000000 0000000000000101

📌 Tips:

  • Memory save → int8, int16
  • Performance / Process easy → int বা int32
  • সব সময় Range এর মধ্যে data থাকবে কিনা তা আগে ভাবুন।

📦 Unsigned Integer Type

Golang এ unsigned int - uint টাইপ হলো এমন সংখ্যা যা কখনোই ঋণাত্মক (negative) হতে পারে না।

  • 👉 শুধুমাত্র ধনাত্মক সংখ্যা (positive) বা শূন্য (0) নিতে পারে।
TypeSizeRange
uint88 bit / 1 byte0 to 255
uint1616 bit / 2 bytes0 to 65,535
uint3232 bit / 4 bytes0 to 4,294,967,295
uint6464 bit / 8 bytes0 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:

typesizePrecision
float3232-bitপ্রায় ৭ দশমিক ঘর পর্যন্ত সঠিক
float6464-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

FormatTypeDescriptionExample
%dintDecimal integer42
%ffloatDecimal float (default precision)3.14
%.2ffloatFloat with 2 decimal points3.14
%sstringString"Hello"
%tbooltrue/falsetrue
%cruneCharacter (Unicode)🙂
%UruneUnicode formatU+1F642
%vanyDefault value (auto detect)true, 42, etc.
%TanyType of the variableint, 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 হয়।


🔒 Defer behaviour for closures

func closureDefer() {
    for i := 1; i <= 3; i++ {
        defer func() {
            fmt.Println("Deferred:", i)
        }()
    }
}

🖨️ Output:

Deferred: 3
Deferred: 2
Deferred: 1

😵‍💫 কেন?

কারণ defer-এর ক্ষেত্রে ফাংশনে ব্যবহৃত ভ্যারিয়েবল গুলো ইমিডিয়েটলি ডিটেক্ট হয় এবং ডেফার স্টাকে সেভাবেই সেভড থাকে


🛠️ Practical Use Cases

  1. File Handling:
func readFile(path string) error {
    f, err := os.Open(path)
    if err != nil {
        return err
    }
    defer f.Close()

    // read file...
    return nil
}
  1. Mutex Unlock:
mu.Lock()
defer mu.Unlock()
// critical section
  1. Recover from panic:
func safe() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered:", r)
        }
    }()
    panic("something went wrong")
}

🧾 Key Takeaways (সংক্ষেপে)

বৈশিষ্ট্যব্যাখ্যা
Execution orderLIFO (Last In, First Out)
Internal structureLinked List with Stack behavior
Named returndefer can modify it
Unnamed returndefer can’t modify it
Use casesFile 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 খেলাও বোঝা জরুরি।

🧵 Class 41 : Separate Stack For Separate Thread

🔁 Recap

  • Thread সম্পর্কে জানতে হবে।
  • Process সম্পর্কে জানতে হবে।
  • SP BP সম্পর্কে ভালো ধারনা থাকতে হবে।

🧠 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 হয়
  • 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 করে

📌 Code Segment, Data Segment, Stack এর size fixed থাকে। Heap dynamically grow / shrink করতে পারে তাই data, Heap এ বেশি রাখা হয়।

🖥️ 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 রাখে

🧠 Operating System core component → Kernel; Kernel process schedule, concurrency / parallelism handle করে।

🧾 Programming language এর উপর depend করে কীভাবে thread create হবে।

📊 Default Stack Sizes by Platform

OSDefault Stack Size (main thread)Default Stack Size (new threads)Notes
🪟 Windows1 MB1 MBCan be changed via linker or CreateThread
🐧 Linux8 MB8 MBControlled by ulimit -s and pthread_attr_setstacksize()
🍎 macOS8 MB512 KBMain thread gets 8MB, but pthread threads get 512KB by default

[Author: @nazma98 Date: 2025-06-19 Category: interview-qa/class-wise ]

Class 42 : ✨ Complex And Beautiful Go Routine

🌀 Goroutine

  • Lightweight thread / Virtual thread
  • Logically thread এর মতো কাজ করে
  • Concurrently অনেকগুলো function execute করে
  • Go Runtime একে manage করে

🛠️ Creating a Goroutine

কোনো function এর আগে go keyword লিখে দিলে সেটা goroutine হয়।

💡 Example

package main

import (
    "fmt"
    "time"
    )

var a = 10

const p = 11

func printHello(num int) {
	fmt.Println("Hello Habib", num)
}

func main() {
	go printHello(1)

	go printHello(2)

	go printHello(3)

	go printHello(4)

	go printHello(5)

	fmt.Println(a, " ", p)

	time.Sleep(5 * time.Second)
}

এই Go কোডে একটা printHello নামের ফাংশন আছে, যেটা "Hello Habib" লিখে সাথে একটা সংখ্যা প্রিন্ট করে।

main() ফাংশনে এই ফাংশনটা ৫ বার goroutine দিয়ে চালানো হয়েছে

সবগুলা goroutine যেন কাজ শেষ করতে পারে, তাই শেষে time.Sleep(5 * time.Second) দিয়ে ৫ সেকেন্ড প্রোগ্রামটাকে অপেক্ষা করানো হয়েছে।

📦 How gorouitne works Internally

Goroutine কীভাবে কাজ করে বুঝার জন্য আমাদের একটি Go program এর compilation, execution phase এবং Thread ভালভাবে বুঝতে হবে।

🔧 Compilation Phase of Go Program

Go program কে compile করার জন্য নিচের command টি ব্যবহার করা হয়

go build main.go
  • এতে একটি binary executable file তৈরি হবে (Linuxmain, Windowsmain.exe)
  • Binary executable file → Code Segment
  • Code Segment → const (read only) → functions
  • main binary executable file store → HDD
                        **Code Segment**

			p = 11
			printHello = printHello() {...}
			main = main() {...}

🚀 Execution Phase of Go Program

Binary executable file run করার জন্য command -

./main
  • Binary executable file load → RAM
  • RAM Memory Layout → Code Segment, Data Segment, Stack, Heap
  • main program → Process create হয়
SegmentPurposeSize / Behavior
Code Segmentcompiled machine code (functions)Fixed size
Data Segmentglobal & static variablesFixed or small
Heapdynamically allocated data (make, etc.)Grows upward
Stackfunction call info, local varsGrows downward, ~8MB (Linux)

যে কোনও programming language (যেমন C, C++, Go, Rust) এর প্রোগ্রাম যখন compile হয়ে binary (.exe / .out) তে convert হয় এবং execution শুরু হয়, তখন একটা process তৈরি হয় এবং সেই process এর জন্য memory তে Code Segment, Data Segment, Stack, Heap থাকে।

🔍 RAM Memory Layout Visualization

┌──────────────────────────┐
│       Heap               │ ← Grows Upward
├──────────────────────────┤
│     Stack (Top ↓)        │ ← Grows Downward
├──────────────────────────┤
│     Data Segment         │ ← Initialized global/static variables
├──────────────────────────┤
│     Code Segment         │ ← Machine Instructions
└──────────────────────────┘

⚙️ Program Execution Process Visualization


HDD ➜ OS Loader ➜ RAM ➜ CPU Executes

📁 HDD (Hard Disk)
│
│  → Executable File (.exe, .out, etc.)
│
▼
📥 Loader (Operating System)
│
│  → Loads program into RAM
│
▼
🧠 RAM (Main Memory)
│
├── 📄 Code Segment        → compiled machine code (instructions)
│
├── 🗃️ Data Segment        → global & static variables
│
├── 📦 Heap Segment        → dynamic memory (malloc/new)
│
├── 📚 Stack Segment       → function calls, local variables
│
▼
⚡ CPU (Processor)
   ├── Fetch → Decode → Execute instructions
   ├── Uses Registers (like AL, BL, etc.)
   └── Uses Stack Pointer (SP), Base Pointer (BP)

🖥️ Process & Thread

  • Process initially একটি Thread থাকে → Deafult Thread / Main Thread
  • Thread কে OS এর kernel execute করলে → Stack execute হয়
  • Stack execute → Stack frame create & execute হয়

🌀 Go Runtime = A Mini OS or Virtual Operating System

Go program → Run → main binary load → Code Segment

⚙️ main Binary – More Than Just Code Segment

  • শুধু code segment নয়
  • আরও অনেক binary থাকে
  • code segment শুধু একটা অংশ মাত্র
  • Thread execute → Process start
  • Process → Virtual computer
  • Go Runtime → Virtual Operating System
  • Process start → Go Runtime execute

🧩 Go Runtime Code Execute

  • Stack → 8MB Stack (main stack) → Stack Frame create
  • main thread execute করে → Go runtime

Go Runtime initialize করে -

  • 1. Go Routine Scheduler
  • 2. Heap Allocator
  • 3. Garbage Collector
  • 4. Logical Processors

Go Routine Scheduler

OS Kernel scheduler → Process schedule, Concurrency, Parallelism handle করে।

Go Routine Scheduler ও Real OS Kernel Scheduler এর মতো কাজ করে।

Logical Processors

🔁 Recap

  • OS এর ভিতর → virtual processors (vCPU) create হয়
  • CPU তে যে কয়টি vCPU (virtual CPU / logical Processor) থাকে → Go Runtime সে কয়টি logical processor create করে
  • প্রতিটি logical processor এর জন্য → OS আলাদা OS Thread create করে
    • CPU 2 core → 4 vCPU
    • Go Runtime initilize করে → 4 logical processors
    • 4 logical processors এর জন্য → OS আলাদা 4 OS Thread create করে
    • 4 OS Thread → 4 stack
    • Total threads in process → 4 (OS thread) + 1 (main thread) → 5 threads
    • OS kernel → 5 threads কে track করে
    • 1 main thread এর জন্য → 1 main stack
    • 4 supporting thread এর জন্য → 4 supporting stack
  • go runtime kernel → go routine schedule করে
    • 4 thread → 10 goroutine execute করে concurrency follow করে

🧠 Go Runtime: OS Thread, Scheduler, and Logical Processor Mapping

                    🌀 Go Runtime Scheduler
                             │
                             ▼
──────────────────────────────────────────────────────
|                   Logical Processors (P)           |
|────────────────────────────────────────────────────|
|      P1               P2              P3           |
|        										     |
|   [G1, G4, G6]     [G2, G5]        [G3, G7, G8]    |
──────────────────────────────────────────────────────
      │               │              │
      ▼               ▼              ▼
  Assigned to     Assigned to    Assigned to
      │               │              │
      ▼               ▼              ▼
─────────────────────────────────────────────
|             OS Threads (M)                 |
|─────────────────────────────────────────── |
|     M1             M2             M3       |
|   (running)     (running)      (idle)      |
─────────────────────────────────────────────
      │               │
      ▼               ▼
   🖥️ CPU Core 1     🖥️ CPU Core 2

Go runtime, OS Thread কীভাবে create করতে হয় সেটি handle করে।

Go runtime শুরুতেই সিস্টেমের vCPU (logical core) অনুযায়ী Logical Processor (P) তৈরি করে।

  • Go Runtime নিজেই একটি kernel এর মতো কাজ করে
  • এই "kernel" এর scheduler থাকে
  • Scheduler, Goroutine গুলোকে execute করতে OS thread কে কাজ ভাগ করে দেয়
  • OS Thread গুলোই CPU তে বসে goroutine গুলো execute করে
  • Go Scheduler ঠিক করে কোন goroutine কখন execute হবে
  • Scheduler OS thread এ map করে thousands of goroutine efficiently চালায়

🖥️ Go Runtime Kernel & Goroutine Scheduling

                       🌀 Go Runtime (Mini Kernel)
                               │
                               ▼
                      🧠 Go Routine Scheduler (Scheduler)
                               │
      -----------------------------------------------------
      |                       |                           |
      ▼                       ▼                           ▼
  G1: Goroutine         G2: Goroutine               G3: Goroutine
 (Task 1)                 (Task 2)                     (Task 3)
      \_______________________|________________________/
                               │
                               ▼
                    📦 Placed into P's Run Queue
                               │
                               ▼
        🔄 Scheduler decides which G to run on which M
                               │
      -----------------------------------------------------
      |                       |                          |
      ▼                       ▼                          ▼
   🧵 M1: OS Thread        🧵 M2: OS Thread           🧵 M3: OS Thread
 (Executes Gs)          (Executes Gs)              (Executes Gs)
      |                       |                          |
      ▼                       ▼                          ▼
   🖥️ CPU Core 1          🖥️ CPU Core 2             🖥️ CPU Core 3


   → G (goroutine)
   → P (Processor)
   → M (OS Thread)

Programmer Goroutine create করে।

📈🧵 Effects of Excessive Goroutines in Go

  • Scheduler notice করে → excessive gorutines
  • Go Runtime → প্রয়োজন অনুযায়ী logical processors & OS Thread create করে
  • RAM full → OS Thread create করা possible হয় না
  • ❌ OS Thread → ❌ Goroutine execution

First যে goroutine run হয় → main goroutine

main function execute হয় → main goroutine এ

🏠 Goroutine's Home: Stack & Heap

Goroutine - mini thread / virtual thread / logical thread

প্রতিটি goroutine

  • এর stack থাকে heap memory এ
  • শুরুতে মাত্র 2KB stack পায়

main() → Main Goroutine

  • Go প্রোগ্রাম রান হলেই main() function চালু হয়
  • এটিই প্রথম goroutine - যাকে বলে Main Goroutine
  • সব normal function call (যেমন f(), g()) এর stack frame তৈরি হয় এই একই stack এ

go functionName() → New Goroutine

go functionName() লিখলে তখন Go runtime:

  • নতুন goroutine তৈরি করে
  • সেটার জন্য আলাদা stack তৈরি করে (initially 2KB)
  • এটিকে scheduling queue তে দেয়

🖼️ Example

var a = 10

const p = 11

func add(a, b int) {
  fmt.Println(a + b)
}

func printHello(num int) {
	fmt.Println("Hello Habib", num)

     add(2, 4)
}

func main() {
    var x int = 10

    fmt.Println("Hello", x)

    printHello(10)

    go printHello(1)

    go printHello(2)

    go printHello(3)

    go printHello(4)

    go printHello(5)

    fmt.Println(a, " ", p)

    time.Sleep(5 * time.Second)
}

Main Goroutine

  • এখানে main() এর জন্য main goroutine create হবে
  • main goroutine এ main(), printHello(10) এবং fmt.Println() এর জন্য Stack Frame create হবে
  • যদি Go program এ init() থাকে তবে init() এর জন্য ও Stack Frame, main goroutine এ create হবে

Other Goroutines

  • printHello() এর জন্য Go runtime ৫টি আলাদা goroutine তৈরি করবে
  • go printHello(1) এর জন্য Heap এ যে goroutine create হয় সেখানে printHello(1), fmt.Println() এবং add(2, 4) এর জন্য Stack Frame create হবে
  • একই ভাবে অন্য goroutine এর জন্যও Stack Frame create হবে

🔍 যদি 2KB Stack যথেষ্ট না হয়

  • ➡️ Go runtime automatically stack এর size বড় করে দেয় (dynamic grow করে)

📈 কিভাবে কাজ করে?

  • শুরুতে: 2KB
  • দরকার হলে: 4KB, 8KB, 16KB... → যত দরকার তত বাড়তে পারে
  • সর্বোচ্চ: 1 GB পর্যন্ত

Go runtime পুরা stack copy করে নতুন বড় stack এ নিয়ে যায়, old stack ফেলে দেয়।

Go Runtime reallocate করতে পারে।

Heap এর Stack এ যে SP, BP থাকে তা মূলত Go Runtime এর initialized logical processor এর SP, BP, return address etc.


                    🧵 Goroutines & Their Stack Memory

┌──────────────────────────────┬─────────────────────────────┬─────────────────────────────┐
│ Goroutine 1 (main)           │ Goroutine 2 (printHello 1)  │ Goroutine 3 (printHello 2)  │
├──────────────────────────────┼─────────────────────────────┼─────────────────────────────┤
│ Stack:                       │ Stack:                      │ Stack:                      │
│ - main()                     │ - printHello(1)             │ - printHello(2)             │
│ - printHello(10)             │ - fmt.Println()             │ - fmt.Println()             │
│ - fmt.Println()              │ - add(2, 4)                 │ - add(2, 4)                 │
└──────────────────────────────┴─────────────────────────────┴─────────────────────────────┘

┌─────────────────────────────┬─────────────────────────────┬──────────────────────────────┐
│ Goroutine 4 (printHello 3)  │ Goroutine 5 (printHello 4)  │ Goroutine 6 (printHello 5)   │
├─────────────────────────────┼─────────────────────────────┼──────────────────────────────┤
│ Stack:                      │ Stack:                      │ Stack:                       │
│ - printHello(3)             │ - printHello(4)             │ - printHello(5)              │
│ - fmt.Println()             │ - fmt.Println()             │ - fmt.Println()              │
│ - add(2, 4)                 │ - add(2, 4)                 │ - add(2, 4)                  │
└─────────────────────────────┴─────────────────────────────┴──────────────────────────────┘

Main goroutine শেষ হলেই পুরো program শেষ, তাই অন্য goroutine চালাতে চাইলে main goroutine কে কিছু সময় বাঁচিয়ে রাখতে হবে ✅

💥 When & How Main Thread, Go Runtime & Main Goroutine Get Destroyed

main thread ≠ main goroutine

ComponentDestruction Point
Main GoroutineEnds when main() returns or panics
Main ThreadExits after main goroutine ends
Go RuntimeTerminates when main goroutine ends
Other GoroutinesForce-killed when main goroutine exits

goroutine গুলো শেষ পর্যন্ত execute করার জন্য main() কে block করে রাখা যায় যেমন:

  • time.Sleep()
  • sync.WaitGroup
  • select {} (infinite block)

🧵 Thread vs Goroutine

FeatureThreadGoroutine
DefinitionOS-level execution unitGo’s lightweight concurrent execution unit
Created ByOperating SystemGo Runtime Scheduler
Memory Usage~1 MB stack (fixed)Starts with ~2 KB stack (grows dynamically)
Creation CostHigh (involves system call)Very Low (simple runtime function)
SchedulingDone by OSDone by Go runtime (user-space scheduler)
CommunicationUsing shared memory, locksUsing channels (safe and built-in)
Concurrency LimitLimited (few thousand max)Huge (millions possible)
BlockingBlocks entire threadBlocking one goroutine doesn’t block others
Context SwitchingCostly (kernel-level)Cheap (user-space context switch)
PortabilityDepends on OSCross-platform (managed by Go)

[Author: @nazma98 Date: 2025-06-24 Category: interview-qa/class-wise ]

🌐 Into The Backend Development


🧱 Static Era of Web Development (Web 1.0)

🔹 সময়কাল: Early 1990s

  • এই সময়কে Web 1.0 বলা হয়।
  • website ছিল একদম Static HTML ফাইলগুলো পূর্বে তৈরি করে সার্ভারে রাখা হতো।

💡 কীভাবে কাজ করতো:

  • User যখন একটি webpage চায়, তখন browser server একটি request পাঠাতো।
  • server সেই HTML ফাইলকে ইউজারের browser এ পাঠিয়ে দিতো।
  • কোনও dynamic content বা user interaction ছিল না।

🖥️ Server কী?

Server একটি কম্পিউটার যেটি নেটওয়ার্কের মাধ্যমে ইউজারের অনুরোধে webpage বা data serve করে।


⚙️ Web 2.0 & Server Side Rendering

🔹 সময়কাল: Mid 1990s - Early 2000s

  • Web 2.0 সময়কালে web dynamic হয়ে উঠল।
  • এখন backend থেকে dynamically generated HTML, CSS পাঠানো শুরু হল।

✨ Backend Programming Language:

  • এই সময়ে জনপ্রিয় কিছু ভাষা ছিল:
    • PHP
    • Java
    • ASP.NET
    • Python

⚡ The AJAX Revolution (2005 - 2010)

🔄 AJAX কী?

AJAX (Asynchronous JavaScript and XML) এর মাধ্যমে browser, page reload না করেই server এর সাথে data আদান-প্রদান করতে পারে।

🔸 API ব্যবহার বাড়ে:

  • AJAX এর মাধ্যমে API-এর গুরুত্ব বাড়ে এবং API endpoint ব্যবহার শুরু হয়।

🔹 API Endpoint কী?

API endpoint হল সার্ভারে নির্দিষ্ট একটি URL যেটি ডেটা রিসিভ বা রিটার্ন করার জন্য ব্যবহৃত হয়।

🕰️ আগের সময়ের তুলনা:

  • AJAX আসার আগে: ইউজারের অনুরোধে পুরো পেইজ রিলোড হতো।
  • AJAX আসার পরে: শুধুমাত্র প্রয়োজনীয় ডেটা JSON আকারে পাঠানো শুরু হয়।

📌 Backend Development এর প্রসার:

  • এই সময় থেকে backend বিশেষভাবে important হয়ে ওঠে API design, authentication, data processing ইত্যাদি কাজ শুরু হয়।

🔄 REST API & JSON (2010)

👨‍🔬 REST-এর জনক:

  • Dr. Roy Fielding
  • REST ধারণা দেন 2000 সালে তার PhD ডিসার্টেশনে।

📖 REST এর পূর্ণরূপ:

Representational State Transfer

📐 REST কী?

REST হচ্ছে একটি software architectural style বা blueprint, যেটা API বানানোর সময় অনুসরণ করা হয়।


🧠 REST Concepts

📌 Representational মানে কী?

Representation বলতে বোঝায় resource এর state কে কিভাবে প্রকাশ করা হচ্ছে।

উদাহরণ: JSON, XML, YAML, HTML ইত্যাদি


📦 Resource & State

🔹 Resource:

Resource হচ্ছে একটি entity বা ধারণা (concept) যেমন: user, post

  • user বলতে আমরা বুঝি একজন মানুষ, কিন্তু কে সে সেটা আমরা জানি না।
  • post বলতে আমরা বুঝি একটি কনটেন্ট, কিন্তু কী পোস্ট করা হয়েছে জানি না।

🔹 State:

Resource-এর বর্তমান অবস্থা বা condition হলো state।

উদাহরণ:

User:
{
  "id": 42,
  "name": "Shahriar",
  "age": 20
}

Post:
{
  "id": 42,
  "title": "Into the backend development",
  "author": "Shahriar"
}

যখন আমরা এই data-কে JSON এর মতো ফরম্যাটে প্রেজেন্ট করি, তখন সেটিকে বলে Representational State


🔁 Transfer কী?

Client যখন কোনও resource চায়, তখন server সেই resource এর state কে JSON বা অন্য ফরম্যাটে represent করে পাঠায়। এটিই হল Representational State Transfer (REST)।


🔍 REST vs RESTful

ধরনবর্ণনা
RESTএকধরনের design principle বা blueprint
RESTfulএমন একটি API বা সার্ভিস যা REST এর principles অনুসরণ করে

একটি RESTful service অনেকগুলি REST API নিয়ে গঠিত হয়।


🧰 What is API?

API (Application Programming Interface) হলো এমন একটি ইন্টারফেস যা দুটি সফটওয়্যারের মধ্যে যোগাযোগ করে।

💬 Frontend ও Backend কিভাবে কথা বলে?

Frontend এবং Backend API-এর মাধ্যমে একে অপরের সাথে যোগাযোগ করে।

উদাহরণস্বরূপ, user form পূরণ করে submit করলে, তা backend API-এর মাধ্যমে প্রক্রিয়াজাত হয় এবং ফলাফল ফিরিয়ে আনা হয়।

[Author : @shahriar-em0n Date: 2025-07-30 Category: interview-qa/class-wise ]

Class 46 : 🐹 Go Runtime

🧠 Guide to RAM: Kernel Space vs User Space

কম্পিউটার চালু হলে RAM (Random Access Memory) কে দুইটা ভাগে ভাগ করা হয়:

  • 🛡️ Kernel Space
  • 👨‍💻 User Space

🛡️ Kernel Space:

এটা Operating System (OS) এর নিজের জন্য allocated space

এখানে থাকে:

  • OS এর মূল কোড (kernel code)
  • kernel data structures
  • page table (memory mapping এর জন্য)

Kernel সব কিছু access করতে পারে।

🔐 Why it's protected?

  • যাতে user program গুলো kernel এর sensitive অংশে ভুল করে বা ইচ্ছা করে access করতে না পারে।
  • Security আর stability এর জন্য।

🧩 Access from user programs

  • User program যদি OS এর help চায়, তখন system call ব্যবহার করে (যেমন read(), write(), open()).
  • তখন একটা software interrupt (যেমন 0x80) তৈরি হয়।
  • এতে CPU user mode থেকে kernel mode এ যায়, kernel কাজটা করে দিয়ে আবার ফিরে আসে।

🧵 Kernel Stack

  • যখন kernel কাজ করে, তখন একটা kernel stack ব্যবহার করে।
  • এটা সব process মিলে share করে।

👨‍💻 User Space:

RAM এর এই space → user application (যেমন browser, notepad) এর জন্য।

প্রতিটা process তার নিজের একটা virtual memory পায়।

এর মধ্যে থাকে:

  • Code: প্রোগ্রামের instruction
  • Data: global বা static variables
  • Heap: dynamic memory allocation (যেমন malloc)
  • Stack: function call আর local variables

⚠️ এই space থেকে kernel space সরাসরি access করা যায় না।

🧩 System Call

  • System Call হলো একধরনের function call
  • এর মাধ্যমে কোন user program, Operating System এর kernel থেকে কোন service চায়
  • System Call এর সাহায্য user mode থেকে kernel mode এ সুইচ করে OS এর বিশেষ কাজগুলো করার অনুমতি দেয়

⚙️ User Mode vs Kernel Mode

  • সাধারণভাবে program চলে user mode এ, যেখানে resource access সীমিত থাকে।
  • কোন special কাজ (যেমন file read/write, process তৈরি) করতে হলে system call দিতে হয়, তখন program kernel mode এ যায়।

✨ Intro to Go Runtime

go build main.go

Go compiler:

  • main.go ফাইলটা compile করে
  • তারপর একটা binary executable file তৈরি করে - সাধারণভাবে সেটা হয় main নামে (Linux/Unix-এ)
./main

একটা process create হয়

🔁 সংক্ষেপে flow:

go build main.go   →  main (binary file)
./main             →  OS creates a process
                   →  program runs

📦 Main Stack এবং Stack Frame

  • Main thread এর জন্য একটি stack তৈরি হয় - এটাকে বলে main stack।
  • Go runtime এর function গুলোর জন্য এই main stack এ stack frames তৈরি হয়।
  • Main thread → execute → go runtime stack

🔹 Stack Frame: প্রতিটা function call এর জন্য একটা stack frame তৈরি হয়।

Stack frame এর মধ্যে থাকে:

  • function এর local variables,
  • return address (function শেষে কোথায় ফিরে যাবে),
  • কিছু runtime bookkeeping data।

🔹Go Runtime -

  • Memory allocate
  • Set up → Stack & Heap
  • Initialize → Go Scheduler
  • Go Runtime → System Call → Kernel → epoll_create

🌀 What is epoll in Linux?

  • epoll হলো Linux kernel এর একটি I/O event notification system
  • এটি ব্যবহার করা হয় একসাথে অনেকগুলো file descriptor (fd) এর ওপর efficiently নজর রাখার জন্য।

এটি select() বা poll() এর থেকে আরও scalable, efficient, এবং faster।

Linux-এর epoll এর মতো high-performance I/O event notification mechanisms অন্য OS-গুলোতেও আছে

🖥️ MacOS (Darwin/BSD) ➤ kqueue

  • Equivalent of epoll in macOS is kqueue.
  • এটি BSD-based systems (macOS, FreeBSD, OpenBSD) এ ব্যবহৃত হয়।

🪟 Windows ➤ IOCP (I/O Completion Ports)

  • Windows-এর equivalent হল ➤ IOCP (I/O Completion Ports)।

🔹 IOCP-এর কাজ:

  • Asynchronous I/O operations handle করতে ব্যবহৃত হয়।
  • Efficient এবং scalable, especially high-performance servers-এর জন্য।

🧠 epoll কবে দরকার হয়?

  • Network socket
  • File
  • Pipe

ইত্যাদি একসাথে monitor করতে এবং কোনটা read/write এর জন্য ready হয়েছে

epfd = epoll_create1(0);                // epoll instance তৈরি
epoll_ctl(epfd, ADD, sockfd, &event);   // কোন socket watch করবো?
epoll_wait(epfd, events, MAX, timeout); // wait করবো কখন data আসবে

🔧 epoll এর জন্য ব্যবহৃত ৩টি main syscall

epoll_create / epoll_create1

  • একটি নতুন epoll instance তৈরি করে এবং একটি file descriptor (fd) রিটার্ন করে।
  • এই fd কে ব্যবহার করে আপনি পরবর্তীতে ইভেন্ট monitor করবেন।

epoll_ctl

  • epoll instance এ কোন file descriptor monitor করতে হবে সেটা বলে দেয়।
  • অর্থাৎ: add / modify / delete operation।

epoll_wait

  • এটি block করে (অপেক্ষা করে) যতক্ষণ না কোন monitored file descriptor থেকে I/O event আসে।
  • যখন আসে, তখন সেই event return করে দেয়।

🏷️ Scenario: epoll-based Non-blocking File Read in Linux

Process & Threads

  • P1: T1, T2
  • P2: T1
  • P3: T1, T2, T3

P1-T1 একটি ফাইল পড়তে চায়, অর্থাৎ I/O operation করতে চায়।

আমরা ধরছি এটা non-blocking I/O এবং epoll ব্যবহৃত হচ্ছে (Linux system)।

১️⃣ T1 ফাইল পড়তে চায়

  • T1 kernel-এ read request পাঠায়, কিন্তু ফাইল তখনও রেডি না।
  • তাই T1 বলে, "ফাইল রেডি হলে আমাকে জানিও" — non-blocking mode

2️⃣ T1 syscall করে → epoll_ctl

  • এটা দিয়ে kernel-কে জানানো হয়:
  • "এই ফাইলের জন্য আমি অপেক্ষা করবো। ফাইলটা read করতে পারলেই আমাকে ডাকো।"

3️⃣ Kernel T1 কে ঘুম পাড়িয়ে দেয়

  • যেহেতু ফাইল এখনো রেডি না, তাই kernel T1 কে sleep/wait করিয়ে দেয়।
  • T1 wait queue তে চলে যায়
  • তখন P1-এর অন্য থ্রেড T2, বা অন্য প্রসেসের থ্রেডগুলো স্বাভাবিকভাবে কাজ করে

4️⃣ kernel ফাইল চেক করতে থাকে

  • kernel backend-এ ফাইল ready কিনা সেটা monitor করে।
  • যখন ফাইলটা readable হয়ে যায়, তখন kernel ফাইলটা load করে, এবং ফাইলের জন্য file descriptor তৈরি করে

5️⃣ kernel epoll কে notify করে

  • kernel epoll_wait কে বলে: "এই file descriptor এখন ready"
  • epoll_wait তখন সেই FD কে ready list-এ রাখে

6️⃣ epoll_wait Thread কে জাগিয়ে তোলে

epoll_wait এর কাজ:

  • যারা অপেক্ষা করছিল, তাদের জানিয়ে দেয়া "তোমার ফাইল রেডি"
  • T1 এখন wake up হয়

7️⃣ T1 এখন read(fd) দিয়ে ফাইল পড়ে

  • এবার T1 ফাইলটি read করে নেয় file descriptor ব্যবহার করে
  • File descriptor একটি token এর মতো কাজ করে — এটি বলে দেয় kernel-এর কোন জায়গা থেকে ফাইল পড়তে হবে

📦 File descriptor

  • File descriptor হচ্ছে kernel-এর একটি token বা ID যা file/socket-এর represent করে।
  • User-space access করতে পারে না, কিন্তু kernel আর Go runtime, file/socket কে চিনে ফেলে এই FD দিয়ে।

🚀 Back to Go Runtime Story

1. Go Runtime শুরুতেই কী করে?

  • Go runtime নিজের মধ্যে একটা epoll instance তৈরি করে (epoll_create syscall ব্যবহার করে)।
  • যখন epoll তৈরি করে, তখন kernel-কে বলে দেয় কতগুলো file descriptor (FD) একসাথে পড়তে চায়
    • Go Runtime kernel-কে বলে দেয় 100 file descriptor (FD) একসাথে পড়তে চায়
    • Max 100 FD read করার জন্য epoll_ctl send করা যাবে kernel এর কাছে
    • 100 FD list আকারে epoll_wait thread কে দিয়ে দিবে
    • epoll_wait thread FD list Go runtime কে দিয়ে দিবে
  • এই instance handle করে সব network I/O বা file I/O অপারেশন।
  • এরপর Go runtime একটি আলাদা OS thread তৈরি করে যেখানে epoll_wait বসে থাকে। এই থ্রেডকে বলা যায় "Netpoller Thread"।

2. একটি goroutine file/socket read করতে চায়

  • main goroutine (যেমন go func() { conn.Read() }) socket থেকে কিছু পড়তে চায়।
  • যদি data তখনই available না থাকে, Go runtime:
    • ওই goroutine কে block না করে park (ঘুম পাড়িয়ে) দেয়।
    • একইসাথে, সেই socket বা file descriptor কে epoll instance-এ register করে রাখে (epoll_ctl দিয়ে)।

3. epoll_wait কী করে?

  • আলাদা Netpoller Thread সবসময় epoll_wait syscall চালিয়ে ঘুমিয়ে থাকে।
  • যখন kernel detect করে যে socket/data ready, তখন সেই Netpoller Thread কে wake করে দিয়ে data দেয়।
  • এরপর Netpoller জানায় যে fd ready।

4. Go Runtime পুনরায় goroutine চালু করে

  • Go runtime বুঝে যায় যে যে goroutine file/socket read করতে চেয়েছিল তার data এসে গেছে।
  • তাকে আবার runnable করে দেয়, এবং data পড়া শুরু হয়।

⚙️ Setting Up Garbage Collector (GC)

  • Go runtime GC চালানোর জন্য আলাদা OS thread ব্যবহার করে, যাতে প্রোগ্রামের মূল কাজ বিঘ্ন না ঘটে
  • thread গুলো background-এ silently কাজ করে memory clean রাখে
  • Go Runtime পুরোপুরি GC thread control করে

🧠 Go Scheduling

Go runtime M:P:G model scheduling follow করে, যেখানে

  • M = Machine (OS-level Thread) — যেটা বাস্তবে CPU-তে কাজ চালায়।
  • P = Processor (Logical Processor) — এটি goroutine run করার জন্য প্রয়োজনীয় execution context ধরে রাখে, যেমন: local run queue, stack, scheduler info ইত্যাদি।
  • G = Goroutine — আমরা যেসব Go function/logic concurrently চালাই, এগুলোকে Go runtime “goroutine” নামে চালায়।

🏗️ Go Scheduler Initialization

M (Machine, বা OS Thread) তৈরি

Go runtime শুরুতেই exactly vCPU সংখ্যক machine thread (M) তৈরির জন্য OS কে request করে।

  • 1 core → 2 vCPU → 2 M
  • 2 core → 4 vCPU → 4 M

P (Logical Processor) তৈরি

🔹 Go runtime M সংখ্যক "Logical Processor" তৈরি করে, যাকে P বলা হয়

  • 4 M : 4 P

🔹 এই P গুলো দেখতে অনেকটা Virtual CPU (vCPU) এর মতো

🔹 কিন্তু এগুলো hardware vCPU না, বরং Go runtime এর internal scheduling unit

G (Goroutine) তৈরি

🔸 Go runtime-এর সবচেয়ে lightweight execution unit হচ্ছে Goroutine (G)

🔸 প্রতিটি go someFunction() কল করলে নতুন একটা goroutine তৈরি হয়

🧩 Go Scheduler: 1M : 1P : 2G Diagram

মনে করি, 1M:1P:2G — এবং মনে হচ্ছে 1P দুইটা goroutine একসাথে চালাচ্ছে, আর 1M চালাচ্ছে সেই 1P-কে

                        ┌──────────────┐
                        │   Machine M  │  ← OS Thread (Executes G via P)
                        └──────┬───────┘
                               │
                               ▼
                        ┌──────────────┐
                        │ Logical P    │  ← Holds G run queue
                        └──────┬───────┘
                               │
                ┌──────────────┴──────────────┐
                ▼                             ▼
        ┌──────────────┐             ┌──────────────┐
        │ Goroutine G1 │             │ Goroutine G2 │
        └──────────────┘             └──────────────┘

🧠 1 Core Scenario in Go Scheduler

✅ Initialization Phase:

  • OS থেকে পাওয়া যায় → 1 Core ⇒ 2 vCPU
  • তাই Go runtime তৈরি করে:
    • 2 Machine Thread (M)
    • 2 Logical Processor (P)
          🧠 Physical Core (1)
                │
        ╔═══════╧════════╗
        ▼                ▼
     M1 (Thread)      M2 (Thread)
       │                 │
       ▼                 ▼
    ┌─────┐           ┌─────┐
    │  P1 │           │  P2 │
    └─┬───┘           └─┬───┘
      │                 │

┌───▼───┐ ┌───▼───┐
│ G1,G2 │ │ G3,G4 │ ← Each P has its G queue
└───────┘ └───────┘

🧪 Run Queue

Go এর scheduler-এ ২ ধরনের run queue থাকে

🧵 ১. Local Run Queue (per P)

প্রতিটি Logical Processor (P) এর নিজস্ব একটি Run Queue থাকে, যেখানে goroutine (G) গুলো রাখা হয়।

🧩 কীভাবে কাজ করে:

  • প্রতিটি P একটি fixed-size circular run queue মেইনটেইন করে যা ring এর মতো
  • প্রতিটি Local Run Queue এর slot 256 → 256 goroutine
  • প্রতিটি P তার queue এর G গুলোকে FIFO ভিত্তিতে চালায় (First-In-First-Out).
  • যেই P বর্তমানে M দ্বারা চালিত হচ্ছে, সেই P তার queue থেকে goroutine G নিয়ে চালায়।
  • যদি কোন G ব্লক করে (I/O, sleep etc), তাহলে P আবার queue থেকে নতুন G চালায়।
  • যদি P এর queue খালি হয়ে যায়, তাহলে:
    • সে work stealing করে — অন্য P এর queue থেকে G চুরি করে নেয়।

🌍 ২. Global Run Queue

যেসব goroutine-কে কোনো নির্দিষ্ট P-তে assign করা যায় না, সেগুলো Global Run Queue-তে রাখা হয়।

  • System-wide queue, সব P access করতে পারে।
  • Locking দরকার পড়ে, তাই একটু ধীর।
  • যখন কোনো P-র local queue খালি হয়, তখন সে Global queue থেকে কাজ নেয়।

🔐 Locking হচ্ছে এমন একটা ব্যবস্থা, যেটা দিয়ে একই সময় একাধিক goroutine যেন একসাথে একই জিনিসে হাত না দিতে পারে, সেটা নিশ্চিত করা হয়।

  • newly created goroutines যে local run queue তে জায়গা পাবে বসে যাবে।

  • logical processor free থাকলে local run queue থেকে goroutine নিয়ে execute করতে থাকে।

  • প্রতিটি local run queue একটি করে goroutine execute করে এবং slot গুলোতে 256 টি করে goroutines থাকলে newly created goroutines গুলো global run queue তে গিয়ে বসে

  • যদি local run queue খালি হয়ে যায়, তাহলে সে অন্য P এর queue থেকে half goroutines নিয়ে নেয় (this is called Work Stealing).

  • কোন processor free হলে এবং এর local run queue তে কোন goroutine না থাকলে, এবং অন্য logical processor এর local run queue তেও goroutines না থাকলে (এক্ষেত্রে work stealing করতে পারেনা) এটি global run queue থেকে goroutines নিয়ে execute করে

🔹 Execution of main.go

package main

import (
	"fmt"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	fmt.Fprintln(w, "hello world")
}

func aboutHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "About page")
}

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("/", handler)
	mux.HandleFunc("/about", aboutHandler)

	fmt.Println("Server running on :8080")
	err := http.ListenAndServe(":8080", mux)
	if err != nil {
		fmt.Println("Error starting server", err)
	}
}
go build main.go
./main

📦 Go Program Memory Layout

                        +----------------------------+
                        |        Code Segment        |
                        |----------------------------|
                        | - func handler             |
                        | - func aboutHandler        |
                        | - func main                |
                        | - imported fmt, net/http   |
                        +----------------------------+

                        +----------------------------+
                        |       Data Segment         |
                        |----------------------------|
                        | - Static/global data       |
                        | - Function/method metadata |
                        | - String constants         |
                        |   e.g., "hello world"      |
                        |         "About page"       |
                        |         ":8080"            |
                        +----------------------------+

                        +----------------------------+
                        |           Heap             |
                        |----------------------------|
                        | - Dynamically allocated    |
                        |   memory during runtime    |
                        | - mux := http.NewServeMux()|
                        | - Each request's data      |
                        | - Goroutines' data         |
                        +----------------------------+

                        +----------------------------+
                        |           Stack            |
                        |----------------------------|
                        | - Go Runtime Code          |
                        |                            |
                        +----------------------------+

🌀 Go HTTP Server Execution

🔹 ১. Go রানটাইম চালু হওয়ার শুরুতে:

  • Go প্রোগ্রাম চালু হলে:
    • প্রথমে init() ফাংশনগুলো (যদি থাকে) execute হয়।
    • এরপর memory layout অনুযায়ী code segment, data segment, ইত্যাদি সেটআপ হয়।

🔹 ২. Main Thread & Stack Setup

  • Go runtime একটা main OS thread তৈরি করে।
  • এই থ্রেডের জন্য একটা main stack allocate করে।
  • এই stack-এ runtime code ও অন্যান্য execution চলবে।

🔹 ৩. Main Goroutine তৈরি

  • Go automatically একটা main goroutine তৈরি করে।
  • এর initial stack size হয় 2KB (heap-এ allocate করা হয়)।
  • এই goroutine থাকবে local run queue-তে।

🔹 ৪. Scheduler এবং Processor

  • Go runtime-এ আছে:
    • M (Machine = Thread)
    • P (Processor = Logical executor)
    • G (Goroutine)
  • যখন Go start হয়, main goroutine local run queue তে enqueue হয়।
  • একটি P (logical processor) active থাকে — শুধু সে কাজ করে কারণ এই মুহূর্তে একমাত্র main goroutine-টাই active।
  • অন্য P গুলো sleep করে থাকবে যদি আর কোনো goroutine না থাকে।

🔹 ৫. main() Function Execution শুরু

  • Main goroutine-এর ভিতর:
    • main() function-এর জন্য একটা stack frame তৈরি হয়।
    • তারপর main() ফাংশনের ভিতরের কোড execute হতে থাকে।

🔹 ৬. Router Creation

  • http.NewServeMux() কল করা হয়:
    • এটি একটি ServeMux object তৈরি করে।
    • এই object টি main goroutine-এর stack frame এ থাকে।

🔹 ৭. Route Register

  • mux.Handle("/", handler):
    • Mux object-এর ভিতরে route pattern ও handler function register হয়।
    • এগুলো map আকারে ServeMux struct-এ store হয়।

🔹 ৮. Server Start

  • http.ListenAndServe(":8080", mux):
    • এটা main goroutine থেকে call হয়।
    • এর জন্য একটি নতুন stack frame তৈরি হয়।

🔹 ৯. Internal serve() Call

  • ListenAndServe() এর ভিতর:
    • srv.Serve(l net.Listener) function call হয়।
    • এর জন্য আরেকটি stack frame তৈরি হয়।

🔂 🔁 ১০. Server-এর Infinite Loop

  • Serve() function-এর ভিতরে থাকে একটি infinite for loop:
    • যেটা প্রতি iteration-এ করে:
      • Accept() করে নতুন connection।
      • প্রতিটি connection এর জন্য নতুন goroutine তৈরি করে।
      • সেই goroutine handle করে HTTP request-response।
Program Start
│
├─> Execute init()
├─> Setup code/data segment
├─> Create main thread + main stack
├─> Create main goroutine (2KB heap stack)
│
└─> main goroutine enqueued → local run queue → executed by P

Main Goroutine:
│
├─> main() stack frame created
│ ├─> mux := http.NewServeMux()
│ ├─> mux.Handle("/", handler)
│ └─> http.ListenAndServe(":8080", mux)
│ └─> srv.Serve(listener)
│ └─> infinite for loop
│ └─> accept conn → new goroutine → handle request
for {
    rw, err := l.Accept()
    go c.serve(connCtx)
}

🧠 Go HTTP Server accepts connection and handles it

🔹 ১. l.Accept() কল হয়

  • এটি একটি network socket accept call।
  • এর জন্য একটি নতুন stack frame তৈরি হয়।
  • এর কাজ হচ্ছে:
    • নতুন কেউ connect করতে চাইলে, তার সাথে communication শুরু করা।

🔹 ২. Accept() কী করে?

  • main goroutine → Accept() call করে → এটি Go runtime কে বলে:
    • “আমাকে একটা socket দাও, যাতে আমি নতুন connection handle করতে পারি।”
    • Go runtime তখন দেখে, “আমার কাছে কি socket আগে থেকেই ready আছে?”

🔹 ৩. Socket না থাকলে কী হয়?

  • যদি socket না থাকে:
    • Go runtime → epoll_ctl() call করে → kernel কে বলে:
      • “তুমি একটা socket তৈরি করো এবং future-এ ready হলে আমাকে জানিও।”
  • এই কাজটা Go-এর netpoll library এর মাধ্যমে করা হয়।

🔹 ৪. epoll_ctl → kernel

  • epoll_ctl() একটা asynchronous system call:
    • মানে এটা main goroutine কে block করে না।
    • Go runtime meanwhile অন্যান্য কাজ চালাতে পারে।

🔹 ৫. Linux kernel কী করে?

  • Linux-এ সবকিছু file হিসেবে treat করা হয় (socket, file, device — সবকিছু)।
  • Kernel একটি socket তৈরি করে — এটা এক প্রান্ত যা দিয়ে data পাঠানো ও গ্রহণ করা যায় (like pipe)।
  • এই socket-এর জন্য kernel একটি file descriptor (FD) দেয়।
    • যেমন, ধরো FD = 5

🔹 ৬. Main Thread Sleep করে

  • main goroutine তখন sleep করে থাকে, কারণ সে অপেক্ষা করছে নতুন socket connection-এর জন্য।
  • কিন্তু এই সময়েও Go runtime বন্ধ হয় না — অন্যান্য goroutine গুলো চালু থাকতে পারে।

🔹 ৭. New Connection এলে

  • কেউ যখন connect করে:
    • Kernel বলে: “এই socket (FD 5) now ready!”
    • Go runtime এর netpoller জেগে উঠে (via epoll_wait) এবং সেই connection গ্রহণ করে।

🔹 ৮. New goroutine handle করে

  • তারপর Go runtime:
    • go c.serve(connCtx) কল করে
    • নতুন goroutine তৈরি হয় → এটি সেই connection এর request/response handle করে
StepDescription
1️⃣Accept() call → নতুন connection চাই
2️⃣Go runtime checks → socket available?
3️⃣না থাকলে → epoll_ctl() → kernel socket তৈরি
4️⃣Kernel → socket তৈরি করে (e.g. FD = 5)
5️⃣main goroutine sleeps → non-blocking epoll
6️⃣New connection এলে → epoll_wait wakes Go runtime
7️⃣go c.serve() → new goroutine handles request

🌐 যখন একটি HTTP Request করা হয় — ভিতরের জগৎ (Go HTTP Server + OS + NIC + Kernel)

🔹 ১. ব্রাউজারে আমরা URL দিই (যেমন: http://localhost:8080/)

  • এই request প্রথমে যায় router → router → server router এর দিকে (DNS resolve ধরে নেওয়া হয়েছে)।

🔹 ২. Server এর Network Interface

  • Server-side এর Network Interface Controller (NIC) — হতে পারে Ethernet Cable বা Wi-Fi Adapter — এই request ধরে।
  • এই NIC data গুলো লেখে তার NIC Receive Buffer (RAM এর একটা অংশ) এ।

**🔹 ৩. NIC Interrupt **

  • যেই মুহূর্তে NIC data পায়, সে তখন Interrupt Signal পাঠায় Kernel কে।
  • Kernel তখন এসে NIC Receive Buffer থেকে data পড়ে।

🔹 ৪. Kernel → Socket Receive Buffer

  • Kernel data কে write করে Socket Receive Buffer এ (যেটা File Descriptor fd 5 এর সাথে যুক্ত)।

🔹 ৫. Kernel → fd 5 Ready

  • এরপর Kernel fd 5 কে ready for read হিসেবে mark করে।

🔹 ৬. epoll_wait() → Wake Up

  • যেহেতু Go runtime epoll_wait() দিয়ে অপেক্ষা করছিল, kernel এখন:
    • সেই sleeping epoll_wait() thread কে wake করে।
    • এবং বলে: “fd 5 এখন ready।”

🔹 ৭. epoll_wait → Go Runtime

  • epoll_wait() এই fd 5 কে Go runtime এর কাছে পাঠায়।

🔹 ৮. Go Runtime → Sleeping Goroutines

  • Go runtime দেখে, “এই fd 5 এর জন্য কোনো goroutine আগে থেকে ঘুমিয়ে ছিলো?”
  • যদি থাকে, তবে সেই goroutine কে wake করে।
  • এরপর Go runtime এর scheduler সেই goroutine কে Local Run Queue তে রাখে।
  • একটি Logical Processor (P) সেই goroutine টি চালানোর জন্য একটি dedicated OS thread (M) পায়।

🔹 🔁 Execution শুরু

  • সেই Logical Processor এখন main goroutine execute করে।
  • Go runtime fd 5 কে main goroutine এর কাছে পাঠায়।

🔹 🔍 Data Read হয়

  • এখন main goroutine fd 5 থেকে data পড়ে
  • socket receive buffer থেকে data আসে
  • rw → data store হয়

🔹 🚀 Serve করার জন্য নতুন goroutine তৈরি

  • এরপর Go runtime go c.serve(connCtx) কল করে
    -নতুন একটা goroutine তৈরি হয়

এই goroutine টি rw তে থাকা data ব্যবহার করে HTTP request handle করে।

🔄 পরবর্তী request-এর জন্য অপেক্ষা

  • এরপর main goroutine আবার l.Accept() এ যায়।
  • Go runtime জানে যে আগেই socket (fd 5) তৈরি হয়েছে।
  • সে এখন new incoming request এর জন্য অপেক্ষা করে।

🔁 নতুন data এলে আবারো একই cycle

  • NIC → kernel → socket receive buffer → mark fd ready → wake epoll_wait

  • Go runtime → wake goroutine → read → serve

এভাবেই একটি HTTP server concurrency + efficiency সহকারে thousands of connections handle করতে পারে।

Client Request (Browser)
↓
Router → Server NIC → NIC Buffer (RAM)
↓ (Interrupt)
Linux Kernel → Copy to Socket Buffer (fd 5)
↓
Mark fd 5 ready → Wake epoll_wait()
↓
Go Runtime → Finds sleeping goroutine
↓
Wake up → Scheduler → Local Run Queue → OS Thread
↓
Execute main goroutine
↓
main goroutine reads from fd 5 → rw = l.Accept()
↓
go c.serve(connCtx) → spawn goroutine to handle
↓
main goroutine again waits for next request...

📦 Newly Spawned goroutine

  • যখন go c.serve(connCtx) এর মাধ্যমে একটি নতুন goroutine spawn করা হয়, তখন একটি নতুন stack তৈরি হয়, এবং এই stack টি heap memory এর মধ্যে সংরক্ষিত হয়।
  • Go তে goroutine এর stack ছোট (প্রথমে 2KB), কিন্তু এটি dynamic ভাবে বাড়তে পারে।
  • এই goroutine টি তারপর local run queue তে যুক্ত হয়, যেখানে অনেক goroutine লাইন ধরে অপেক্ষা করে।
  • প্রতিটি logical processor (P) এর সাথে একটি dedicated OS thread (M) mapped থাকে। এই logical processor (P) সেই local run queue থেকে goroutine টিকে তুলে নেয় এবং execution শুরু করে।

🧵 goroutine spawn = “নতুন একটি lightweight thread তৈরি করে সেটাকে চালু করা।”

✅ mux এবং handler execution ধাপ:

  • এর আগে server এর মধ্যে mux (যেমন http.NewServeMux()) তৈরি করা হয়েছে এবং সেখানে HandleFunc() এর মাধ্যমে route ও handler function register করা হয়েছে।
  • goroutine ওই router-এর মধ্যে খুঁজে দেখে, request-এর URL path /about এর মতো কোন route এর সাথে match করে কিনা।
  • নতুন goroutine যখন চালু হয়, তখন request-এর URL path, header, এবং অন্যান্য metadata দেখে বোঝার চেষ্টা করে, কোন route বা path টি মিলে যাচ্ছে।
  • যখন একটি HTTP request আসে, তখন router চেক করে সেই URL path এর সাথে কোন pattern match করছে এবং সেই অনুযায়ী handler function execute করে।
    • যেমন goroutine ওই router-এর মধ্যে খুঁজে দেখে, request-এর URL path /about এর মতো কোন route এর সাথে match করে কিনা।
    • /about path এর জন্য aboutHandler() নামের handler function register করা আছে।
  • handler match হবার পর, সেই matched handler function এর জন্য একটি নতুন stack frame তৈরি হয়, যাতে ওই ফাংশনটি তার কোড execute করতে পারে।
    • যখন aboutHandler() চালু হয়:
      • তার জন্য একটি নতুন stack frame তৈরি হয়, যাতে ফাংশনের ভিতরের কোড execute করা যায়।
      • এই ফাংশন w (response writer) & fprintln এর মাধ্যমে socket এর কাছে "About page" write করে।
      • socket send buffer এ syscall এর মাধ্যমে data store হয়।

🧠 NIC-এ ডেটা যাওয়ার প্রসেস

  • Go app থেকে socket
    • fmt.Fprintln(w, "About page") → Go runtime ResponseWriter এর ভিতরে Write() method call করে → অবশেষে syscall.Write() এর মাধ্যমে kernel socket send buffer এ data জমা হয়।
    • ResponseWriter.Write() → অবশেষে Go syscall layer-এ গিয়ে syscall.Write() call হয়।
    • syscall.Write() এর মাধ্যমে data kernel space-এ যায় এবং Socket Send Buffer এ জমা হয়।
    • Kernel তখন socket FD (File Descriptor) অনুযায়ী check করে data ready কিনা।
  • Kernel থেকে NIC
    • Kernel-এর network stack সেই data কে প্যাকেট করে (TCP/IP header সহ) NIC-এর TX (Transmit) ring buffer-এ লেখা হয় (এটা hardware circular queue)।
  • NIC প্যাকেট নেয় এবং Physical Layer-এ পাঠায়
    • NIC Controller → DMA (Direct Memory Access) দিয়ে data ring buffer থেকে পড়ে → electromagnetic signal আকারে Ethernet cable / WiFi দিয়ে router/switch-এর দিকে পাঠায়।
  • Router hopping
    • একাধিক router, switch এবং network node পার হয়ে destination client (user-এর PC বা mobile) পর্যন্ত পৌঁছায়।
  • Client receives
    • Client এর NIC → OS → Browser → renders "About page"
+--------------------+               +-----------------+
|  Go Application    |               |     Kernel      |
|--------------------|               |-----------------|
| fmt.Fprintln(w,…)  |               |                 |
|   ↓                |               | syscall.Write() |
| ResponseWriter     |               |   ↓             |
|   ↓                |               | Socket Buffer   |
+--------------------+               |   ↓             |
                                     | NIC Driver      |
                                     +--------↓--------+
                                              |
                           +------------------↓-------------------+
                           |       NIC TX Ring Buffer (DMA)       |
                           +------------------↓-------------------+
                                              |
                                 Electromagnetic Signal
                                              ↓
                                        Ethernet/WiFi
                                              ↓
                                           Router
                                              ↓
                                          Client PC
                                        "About page"

TermMeaning
Socket2-way data pipe, communication endpoint
File Descriptor (FD)kernel-assigned number for tracking sockets/files
epoll_ctlkernel কে বলি — “এই socket ready হলে আমাকে জানিও”
epoll_waitGo runtime waits here — non-blocking
goroutineGo-এর ultra-light thread — request handle করে

[Author: @nazma98 Date: 2025-07-30 Category: interview-qa/class-wise ]

Topic wise

[Author: @mdimamhosen, @mahabubulhasibshawon Date: 2025-04-19 Category: interview-qa/arrays Tags: [go, arrays, functions] ]

Go তে Array

Array declare করা

Go-তে নিচের syntax ব্যবহার করে array declare করা যায়:

var arrayName [size]elementType

উদাহরণ:

var numbers [5]int

Arrays initialize করা

Array declare করার সময় Array initialize করা যেতে পারে:

var numbers = [5]int{1, 2, 3, 4, 5}

অথবা short-hand notation ব্যবহার করতে পারেন:

numbers := [5]int{1, 2, 3, 4, 5}

Array element access করা

Array এর element index ব্যবহার করে access করা যায়, যেটি 0 থেকে শুরু হয়:

fmt.Println(numbers[0]) // Output: 1

Array তে loop run করা

for loop ব্যবহার করে Array উপর loop run করা যায়:

for i := 0; i < len(numbers); i++ {
    fmt.Println(numbers[i])
}

অথবা range keyword ব্যবহার করতে পারেন:

for index, value := range numbers {
    fmt.Println(index, value)
}

Multidimensional Arrays

Go multidimensional array সাপোর্ট করে। একটি two-dimensional array নিচেরভাবে declare করা হয়:

var matrix [3][3]int

উদাহরণ:

matrix := [3][3]int{
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9},
}

Array of Arrays

array of arrays হলো এমন একটি data structure, যেখানে একটি array প্রতিটি element আরেকটি array বা slice। এটি সাধারণত variable সাইজের 2D data রাখার জন্য ব্যবহৃত হয়, যেমন প্রতিটি row তে ভিন্ন ভিন্ন element থাকতে পারে।

উদাহরণ:

arrayOfArrays := [][]int{
    {1, 2},
    {3, 4, 5},
    {6},
}

ফাংশনে Arrays পাঠানো

Go-তে array ফাংশনে পাঠানো হয় value হিসেবে, অর্থাৎ ফাংশনটি array এর একটি copy পায়:

func printArray(arr [5]int) {
    for i := 0; i < len(arr); i++ {
        fmt.Println(arr[i])
    }
}

মূল array পরিবর্তন করতে হলে, আপনাকে array এর pointer পাঠাতে হবে:

func modifyArray(arr *[5]int) {
    arr[0] = 100
}

Frequently Asked Questions

Q1: Go-তে কিভাবে array এর দৈর্ঘ্য নির্ধারণ করব?

array এর দৈর্ঘ্য নির্ধারণ করতে len() built-in function ব্যবহার করুন।

উদাহরণ:

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: Go-তে কিভাবে একটি array copy করব?

Go-তে array copy করার জন্য আপনি সেটিকে একই type এবং size এর অন্য array তে assign করতে পারেন।

উদাহরণ:

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: কিভাবে copy না করে function এ array পাঠিয়ে সেটিকে পরিবর্তন করা যায়?

copy না করে পরিবর্তন করতে চাইলে array এর pointer পাঠান।

উদাহরণ:

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]
}

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, @n8fury Date: 2025-04-19 Category: interview-qa/boolean Tags: [go, boolean, data-types] ]

একটি boolean data-type হয় "TRUE" অথবা "FALSE" হতে পারে

package main
import "fmt"
func main() {
 isGolangPL := true
 isHtmlPL := false
 fmt.Println(isGolangPL)
 fmt.Println(isHtmlPL)
}

Frequently Asked Questions

Q1: conditional statement এ boolean value কিভাবে ব্যবহার করব?

উত্তর: Boolean value সাধারণত conditional statement এ program এর flow control করার জন্য ব্যবহার করা হয়। উদাহরণ:

package main
import "fmt"
func main() {
 isEven := true
 if isEven {
  fmt.Println("The number is even.")
 } else {
  fmt.Println("The number is odd.")
 }
}

Q2: boolean value গুলো কি সরাসরি compare করা যায়?

উত্তর: হ্যাঁ, boolean value গুলো comparison operator ব্যবহার করে সরাসরি compare করা যায়। উদাহরণ:

package main
import "fmt"
func main() {
 isTrue := true
 isFalse := false
 fmt.Println(isTrue == isFalse) // আউটপুট: false
 fmt.Println(isTrue != isFalse) // আউটপুট: 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, @mahabubulhasibshawon Date: 2025-04-22 Category: interview-qa/arrays Tags: [go, clousers, functions] ]

Closure

🔁 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 ধাপসমূহ

🧩 ধাপ ১: Compilation

  • Compile করে binary তৈরি করুন:
go build main.go

🚀 ধাপ ২: Execution

  • Binary run করুন:
./main

🔒 Go-তে Closures

✅ Closure কী?

Closure হলো এমন একটি funtion, যা অন্য একটি funtion এর ভিতরে define করা হয় এবং যা তার নিজের scope ছাড়াও তার outer scope থাকা variable গুলোকে মনে রাখে এবং ব্যবহার করতে পারে, এমনকি সেই outer scope টি execute হওয়া শেষ হয়ে গেলেও।

func Outer() func() {
    money := 100
    show := func() {
        money += 10
        fmt.Println("Money:", money)
    }
    return show
}
  • money variable টি inner function দ্বারা capture করা হয়।
  • প্রতিবার call করলে money update হয়।

✅ Multiple Closures

  • প্রতিবার Outer() call করলে নতুন money instance তৈরি হয়, যা অন্যগুলোর থেকে আলাদা।

🧠 Output ব্যাখ্যা

init() runs first: ============ Begin ============

Outer function  
Age: 20  
Money: 130  
Money: 160  
=========================  
Outer function  
Age: 20  
Money: 130  
Money: 160
  • দুইটি closure তৈরি হয়েছে, প্রতিটির নিজস্ব money instance আছে।
  • এরা একে অপরকে প্রভাবিত করে না।

🧱 Memory segment বিশ্লেষণ

segmentকী সংরক্ষণ করে
Code segmentcompile করা নির্দেশাবলী এবং constant (a, main, call, Outer, init, show)
Data segmentGlobal variable b
StackLocal variable (age), function call frame
HeapCloser ও Escaping variable (money)

🧠 Visualization

CLI-style Memory বিন্যাস

┌──────────────────────────────┐
│        Code segment          │
│------------------------------│
│ const a = 10,                │
│ func main, call, Outer, init │
│ show (anonymous function)    │
└──────────────────────────────┘
          ↓
┌──────────────────────────────┐
│        Data segment         │
│------------------------------│
│ var b = 20                   │
└──────────────────────────────┘
          ↓
┌──────────────────────────────┐
│           Stack              │
│------------------------------│
│ Outer() frame                │
│   age = 20                   │
│   return address             │
└──────────────────────────────┘
          ↓
┌──────────────────────────────┐
│            Heap               │
│------------------------------│
│ money = 100 (inc)            │
│ money = 130 (after inc())    │
│ money = 160 (after inc())    │
│                              │
│ money = 100 (inc1)           │
│ money = 130 (after inc1())   │
│ money = 160 (after inc1())   │
└──────────────────────────────┘

🧠 ব্যাখ্যা:

  • ab Global — তাই a Code segment (const), আর b Data segment এ যায়।
  • age একটি Local variable, এবং কেবল Outer function ব্যবহৃত — Stack থাকে।
  • money একটি Closer এর অংশ, কারণ show() function এর মধ্যে ব্যবহৃত ও return করা হচ্ছে — তাই এটি Heap এ সংরক্ষিত।
  • প্রতিবার Outer() call হলে, নতুন money variable Heap তৈরি হয়, আলাদা করে (inc, inc1)।

🔍 Types of Closures

1. Closure with Outer Variable

প্রশ্ন: একটি Go program লিখুন যা দেখায় কীভাবে closure outer function থেকে variable access ও modify করতে পারে।

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
}

ব্যাখ্যা:

  • outer function একটি closure তৈরি করে যা x ভেরিয়েবল capture করে এবং modify করে।
  • প্রতিবার call করলে x এর মান বাড়ে।

2. Multiple Closures with Separate States

প্রশ্ন: দেখান কীভাবে একই function এ তৈরি হওয়া একাধিক closures তাদের নিজস্ব 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
}

ব্যাখ্যা:

  • counter1 এবং counter2 প্রতিটিই আলাদা closure, যাদের নিজস্ব counter state রয়েছে।
  • এরা একে অপরকে প্রভাবিত করে না।

3. Closure with Parameters

প্রশ্ন: এমন একটি closure লিখুন যা parameter accept করে এবং দেখায় যে closures কীভাবে 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
}

ব্যাখ্যা:

  • multiplier নামের closure factor parameter accept করে এবং একটি function return করে যা n কে factor দিয়ে গুণ করে।
  • double এবং triple আলাদা আলাদা factor ব্যবহার করে।

4. Closures with Deferred Execution

প্রশ্ন: Go-তে closures কীভাবে deferred execution এর সঙ্গে ব্যবহার করা যায় এবং outer function শেষ হওয়ার পর variable access করলে কী ঘটে?

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)
}

ব্যাখ্যা:

  • যদিও maina পরিবর্তিত হয়েছে, deferred closure-এ a এর যে মান পাঠানো হয়েছে সেটাই print হবে।
  • কারণ a parameter হিসেবে capture করা হয়েছে, reference নয়।

5. Closure Capturing Loop Variable

প্রশ্ন: একটি Go program লিখুন যা দেখায় কীভাবে closure loop variable ভুলভাবে capture করে।

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()
    }
}

ব্যাখ্যা:

  • সব closures একই i variable capture করে।
  • loop শেষ হওয়ার পরে i এর মান হয় 3, তাই সব output হয় 3।
  • এটা ঠিক করার জন্য এর i মান parameter হিসাবে closures এ পাঠাতে হবে।

সঠিক 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

প্রশ্ন: এমন একটি closure তৈরি করুন যা দুটি সংখ্যা যোগ করে এবং দেখায় কীভাবে closures argument capture করে।

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
}

ব্যাখ্যা:

  • adder function a কে capture করে এবং b এর সাথে যোগ করে।
  • add5 closure a = 5 মনে রাখে এবং তার সাথে নতুন b যোগ করে।

7. Closures with a Function Factory

প্রশ্ন: একটি closure তৈরি করুন যা function factory হিসেবে কাজ করে এবং pass করা argument অনুসারে বিভিন্ন mathematical operation return করে।

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
}

ব্যাখ্যা:

  • operationFactory pass করা operator অনুযায়ী একটি closure return করে।
  • প্রতিটি closure নির্দিষ্ট operation সম্পাদন করে।

8. Closures with State Preservation

প্রশ্ন: এমন একটি closure লিখুন যা বারবার call করার পরও তার state সংরক্ষণ করে (যেমন একটি simple counter)

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
}

ব্যাখ্যা:

  • প্রতিটি counter() call একটি নতুন count variable সহ closure তৈরি করে।
  • c1 এবং c2 আলাদা আলাদা state সংরক্ষণ করে।

9. Closure with Function Composition

প্রশ্ন: একটি Go প্রোগ্রাম তৈরি করুন যা closures ব্যবহার করে function composition demonstrate করে।

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)
}

ব্যাখ্যা:

  • compose function দুটি function f এবং g accept করে এবং একটি নতুন function return করে যা g(x) এর ওপর f() apply করে।
  • এখানে double(addFive(3)) => double(8) => 16

Go Closures - code উদাহরণ ও ব্যাখ্যাসহ ২০টি প্রশ্ন

এই document Go-এর closures নিয়ে ২০টি প্রশ্ন, code উদাহরণ এবং বিস্তারিত ব্যাখ্যা রয়েছে।


1. Go-তে closure কী?

প্রশ্ন: Go-এ closure কী তা ব্যাখ্যা করুন একটি উদাহরণসহ।

Code:

package main

import "fmt"

func outer() func() {
    return func() {
        fmt.Println("This is a closure")
    }
}

func main() {
    closure := outer()
    closure()
}

ব্যাখ্যা:
একটি closure এমন একটি function যা তার চারপাশের scope থেকে variable ধরে রাখতে পারে। উপরের উদাহরণে outer function যেটি return করছে সেটি একটি closure, কারণ এটি তার তৈরি হওয়া environment-এর context access করতে পারে।


2. একটি closure কীভাবে outer function-এর variable access করে?

প্রশ্ন: দেখান কিভাবে একটি closure outer variable access ও modify করতে পারে।

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
}

ব্যাখ্যা:
এই closure outer x variable ধরে রাখে এবং প্রতিবার call করার সময় তাকে modify করে।


3. closure যখন loop-এর variable access করে তখন কী হয়?

প্রশ্ন: closure দ্বারা loop variable capture করার সময় কী ধরনের ভুল হতে পারে তা দেখান।

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()
    }
}

ব্যাখ্যা:
এখানে সবগুলো closure একই i variable ধরে রাখে, তাই প্রত্যেকটা closure call করার সময় 3 print হয়। কারণ loop শেষ হবার পর i এর final value 3 হয়ে যায়, এবং closure সেই reference-টাই ধরে রাখে।


4. loop closure সমস্যা কীভাবে সমাধান করবেন?

প্রশ্ন: loop-এর প্রতিটি iteration-এ আলাদা variable কিভাবে capture করবেন?

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()
    }
}

ব্যাখ্যা:
i := i দিয়ে প্রতি iteration-এ নতুন i তৈরি হওয়ায়, closure গুলো ভিন্ন ভিন্ন value ধরে রাখে এবং আলাদা আলাদা output দেয়: 0, 1, 2


5. Function parameter হিসেবে closure

প্রশ্ন: কিভাবে closure-কে অন্য function-এ argument হিসেবে pass করবেন?

Code:

package main

import "fmt"

func applyClosure(f func()) {
    f()
}

func main() {
    closure := func() {
        fmt.Println("Closure passed as argument")
    }
    applyClosure(closure)
}

ব্যাখ্যা:
closure-কে কোনো function-এর argument হিসেবে pass করা যায়। এখানে applyClosure function-টি একটি closure নেয় এবং তাকে execute করে।


6. parameter সহ closure

প্রশ্ন: একটি closure লিখুন যেটি একটি parameter নেয় ?

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
}

ব্যাখ্যা:
এই closure factor ধরে রাখে এবং return করা function n এর সাথে তাকে গুণ করে। এইভাবে double(4) output দেয় 8


7. closure যখন value return করে

প্রশ্ন: দেখান কিভাবে closure return value দেয়।

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
}

ব্যাখ্যা:
এই closure a ধরে রাখে এবং প্রতিবার নতুন input b এর সাথে তা যোগ করে result return করে।


8. একটি function থেকে closure return করা

প্রশ্ন: দেখান কিভাবে একটি function closure return করতে পারে।

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
}

ব্যাখ্যা:
createCounter প্রত্যেকবার call করলে নতুন একটি closure return করে যার নিজস্ব counter থাকে।


9. closure যেটি তার পূর্ববর্তী state মনে রাখে

প্রশ্ন: এমন একটি closure লিখুন যা আগের state ধরে রাখতে পারে।

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
}

ব্যাখ্যা:
প্রতিটি closure আলাদা count ধরে রাখে। তাই c1 এবং c2 এর মধ্যে একে অপরের সাথে কোনো সম্পর্ক নেই।


10. closure এবং anonymous function

প্রশ্ন: কিভাবে anonymous function ব্যবহার করে closure তৈরি করা যায়?

Code:

package main

import "fmt"

func main() {
    a := 5
    closure := func() {
        fmt.Println("Captured value:", a)
    }
    closure() // Output: Captured value: 5
}

ব্যাখ্যা:
anonymous function closure হিসেবে কাজ করতে পারে। এখানে a variable টি capture করে রেখেছে function টা।



11. Closure দিয়ে lazy evaluation

প্রশ্ন: কিভাবে closure ব্যবহার করে lazy evaluation করা যায়?

Code:

package main

import "fmt"

func lazySum(a, b int) func() int {
    return func() int {
        return a + b
    }
}

func main() {
    sum := lazySum(3, 4)
    fmt.Println("Doing something else...")
    fmt.Println("Now evaluating sum:", sum())
}

ব্যাখ্যা:
এই উদাহরণে, lazySum function টি actual calculation defer করে রাখে যতক্ষণ না sum() call করা হয়।


12. Closure ব্যবহার করে filter function তৈরি করা

প্রশ্ন: কিভাবে closure ব্যবহার করে একটি filter function তৈরি করা যায়?

Code:

package main

import "fmt"

func filter(data []int, predicate func(int) bool) []int {
    result := []int{}
    for _, v := range data {
        if predicate(v) {
            result = append(result, v)
        }
    }
    return result
}

func main() {
    nums := []int{1, 2, 3, 4, 5}
    even := func(n int) bool {
        return n%2 == 0
    }
    fmt.Println(filter(nums, even)) // Output: [2 4]
}

ব্যাখ্যা:
filter function টি একটি closure নেয় যেটি প্রতিটি item evaluate করে। এখানে, even একটি closure যা শুধু জোড় সংখ্যা বেছে নেয়।


13. Closure দিয়ে memoization

প্রশ্ন: কিভাবে closure ব্যবহার করে memoization implement করা যায়?

Code:

package main

import "fmt"

func memoize() func(int) int {
    cache := map[int]int{}
    return func(n int) int {
        if val, ok := cache[n]; ok {
            return val
        }
        result := n * n
        cache[n] = result
        return result
    }
}

func main() {
    square := memoize()
    fmt.Println(square(4)) // Output: 16
    fmt.Println(square(4)) // Cached output: 16
}

ব্যাখ্যা:
এই closure একটি map-এর মাধ্যমে আগে হিসাব করা ফলাফল মনে রাখে। একই input দিলে সে পুরোনো result ব্যবহার করে।


14. Closure দিয়ে callback implement করা

প্রশ্ন: কিভাবে closure ব্যবহার করে callback তৈরি করা যায়?

Code:

package main

import "fmt"

func doSomething(callback func(string)) {
    callback("Hello from callback")
}

func main() {
    doSomething(func(msg string) {
        fmt.Println(msg)
    })
}

ব্যাখ্যা:
closure callback হিসেবে কাজ করছে যা doSomething function থেকে invoke হচ্ছে।


15. Closure এবং goroutine

প্রশ্ন: closure কিভাবে goroutine এর মধ্যে ব্যবহার করা যায়?

Code:

package main

import (
    "fmt"
    "time"
)

func main() {
    for i := 0; i < 3; i++ {
        i := i
        go func() {
            fmt.Println(i)
        }()
    }
    time.Sleep(1 * time.Second)
}

ব্যাখ্যা:
closure গুলো goroutine এর মধ্যে চলেছে। i := i দিয়ে প্রতি iteration-এ আলাদা value ensure করা হয়েছে।


16. Closure scope এর প্রভাব

প্রশ্ন: একটি closure কিভাবে ভিন্ন scope এ ভিন্ন আচরণ করে?

Code:

package main

import "fmt"

func main() {
    x := 5
    {
        x := 10
        closure := func() {
            fmt.Println(x)
        }
        closure() // Output: 10
    }
}

ব্যাখ্যা:
closure সেই scope-এর variable ধরে যেখানে এটি define হয়েছে। এখানে closure x := 10 এর value ধরে রেখেছে।


17. Closure-এ pointer capture করা

প্রশ্ন: কিভাবে closure pointer capture করে ?

Code:

package main

import "fmt"

func main() {
    x := 10
    ptr := &x

    closure := func() {
        fmt.Println(*ptr)
    }

    x = 20
    closure() // Output: 20
}

ব্যাখ্যা:
closure একটি pointer ধরে রাখলে, variable-এর যে কোনো পরিবর্তন সে reflect করবে কারণ address ধরেই access হয়।


18. Closure reference vs value capture

প্রশ্ন: Go-তে closure variable কে reference না value হিসাবে ধরে রাখে?

Code:

package main

import "fmt"

func main() {
    x := 10
    closure := func(val int) {
        fmt.Println(val)
    }

    x = 20
    closure(x) // Output: 20
}

ব্যাখ্যা:
যখন আপনি closure-এ variable pass করেন (যেমন val int), তখন সেটি value হিসাবে যায়। তবে যদি variable capture করা হয় closure scope-এ, সেটা reference এর মতো behave করে।


19. Closure এবং defer

প্রশ্ন: closure কিভাবে defer statement এর সঙ্গে কাজ করে?

Code:

package main

import "fmt"

func main() {
    for i := 0; i < 3; i++ {
        i := i
        defer func() {
            fmt.Println(i)
        }()
    }
}

ব্যাখ্যা:
সব defer statement পরে একসাথে execute হয় (LIFO)। এখানে i := i দিয়ে প্রতিটি closure আলাদা value capture করে।


20. Closure debugging এর টিপস

প্রশ্ন: closure ব্যবহার করার সময় common debugging সমস্যা ও সমাধান কী?

Explanation (no code):

  • loop variable capture করলে সব closure একই variable reference ধরে রাখতে পারে (সমস্যা)। সমাধান: নতুন variable declare করে capture করা।
  • closure asynchronous context (যেমন goroutine) এ ব্যবহার করলে, race condition তৈরি হতে পারে। সমাধান: value copy করে capture করা।
  • closure capturing unexpected state? সরাসরি log print করুন বা debugger দিয়ে scoped variable inspect করুন।

[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

OperatorNameExample
==Equal tox == y
!=Not equalx != y
>Greater thanx > y
<Less thanx < y
>=Greater than or equal tox >= y
<=Less than or equal tox <= 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.

Golang Routine Channel - Golang Gopher@clipartmax.com

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:

  1. Goroutine Creation: When a goroutine is created (via go keyword), it’s added to a run queue managed by a P.
  2. 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.
  3. Work Stealing: If a P’s run queue is empty, it can steal goroutines from another P’s queue, balancing the workload.
  4. Preemption: The scheduler can preempt long-running goroutines (e.g., during function calls or blocking operations like syscalls) to ensure fairness.
  5. 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:

  1. 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:
      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)
      }
      
      Here, the main goroutine waits for the message, ensuring synchronization.
  2. sync.WaitGroup:

    • Used to wait for multiple goroutines to complete.
    • Methods: Add(n) to set the number of goroutines, Done() to signal completion, and Wait() 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")
      }
      
  3. 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 to n 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), where n 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, making select 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 either ch1 or ch2 to send a value.
  • After 1 second, ch1 sends, and select processes it.
  • After another second, ch2 sends, and select 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, or go 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 on counter.

Preventing Race Conditions:

  1. Mutexes:

    • Use sync.Mutex to ensure exclusive access to shared data.
    • Example:
      var mu sync.Mutex
      func increment() {
          mu.Lock()
          counter++
          mu.Unlock()
      }
      
  2. 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)
      }
      
  3. Atomic Operations:

    • Use sync/atomic for simple operations like counters.
    • Example:
      var counter int64
      func increment() {
          atomic.AddInt64(&counter, 1)
      }
      
  4. 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 call Add() again.
  • Common Pitfall: Calling Done() without a corresponding Add() or calling Add() after Wait() 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:

  1. Create a channel for tasks (jobs).
  2. Launch a fixed number of worker goroutines that read from the task channel.
  3. Send tasks to the channel.
  4. Collect results (if needed) via another channel.
  5. 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 to results.
  • 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 with recover() to catch and handle panics within a goroutine.
  • recover() returns the value passed to panic() if called in a deferred function; otherwise, it returns nil.
  • 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 to false in v, 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, a nil channel is effectively ignored, as its operations are never ready.
  • 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 like pprof.

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

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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, @mahabubulhasibshawon 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

First-Order Function এমন একটি function, যা সাধারণ data type (যেমন int, string ইত্যাদি) এর উপর কাজ করে এবং কোনো function কে ইনপুট হিসেবে নেয় না বা return করে না।

Higher-Order Function

Higher-Order Function এমন function, যা অন্য function কে argument হিসেবে নিতে পারে এবং/অথবা function return করতে পারে। Higher-Order Function functional programming paradigm এ খুব গুরুত্বপূর্ণ ভূমিকা রাখে।

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

Discrete Mathmatics-এ, logic ব্যবহার করা হয় object এর property এবং তাদের relation বিশ্লেষণ করার জন্য।

  1. Object: এমন কিছু যার বাস্তব অস্তিত্ব আছে (যেমন: মানুষ, প্রাণী)
  2. Property: Object-এর বৈশিষ্ট্য বা গুণ (যেমন: রং, উচ্চতা)
  3. Relation: কিভাবে object-গুলো একে অপরের সাথে সম্পর্কযুক্ত (যেমন: "all customers must pay their pizza bills")

উদাহরণ:

  • Object: Customer

  • Property: Has a bill

  • Relation: Must pay the bill

  • First-Order Logic: Object, property এবং relation নিয়ে কাজ করে।

  • Higher-Order Logic: function এর মধ্যকার relation বা operations নিয়ে কাজ করে।

function এর ক্ষেত্রে:

  • First-Order Function: সরাসরি object ও তার properties এর উপর কাজ করে।
  • Higher-Order Function: function এর মধ্যকার relation নিয়ে কাজ করে, যেটা আরও abstract ও flexible operations করতে সাহায্য করে।

Functional Paradigms

Functional programming এমন একটি programming paradigm যেখানে program গঠন করা হয় function apply এবং compose করার মাধ্যমে। এই paradigm জোর দেওয়া হয় pure functions, immutability, এবং higher-order functions এর উপর।

  • Pure Functions: একই input সব সময় একই output দেয়, এবং কোনো side effect থাকে না।
  • Immutability: একবার data তৈরি হলে তা পরিবর্তন করা যায় না; পরিবর্তনের জন্য নতুন data তৈরি করা হয়।
  • First-Class Functions: function গুলোকে variable এ রাখা যায়, argument হিসেবে পাঠানো যায় এবং অন্য function থেকে return করা যায়।
  • Higher-Order Functions: functionগুলো অন্য function কে argument হিসেবে নিতে পারে বা return করতে পারে।

Haskell, Racket, এবং Lisp এর মতো functional programming ভাষাগুলো function নিয়ে কাজ করার জন্য শক্তিশালী abstraction দেয়।

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: একটি higher-order function এমন function, যেটা অন্য function কে parameter হিসেবে নিতে পারে অথবা অন্য কোনো functionকে return করতে পারে অথবা উভয়ই করতে পারে।

উদাহরণ:

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: একটি first-order function হলো এমন function, যা শুধুমাত্র সাধারন data type নিয়ে কাজ করে এবং অন্য কোনো function কে parameter হিসেবে নেয় না বা return করে না।

উদাহরণ:

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: হ্যাঁ, একটি higher-order function তৈরি করা যায় যেটা আরেকটি function return করে।

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: Anonymous function হলো এমন একটি function যার নাম নেই। সাধারণত ছোট বা একবারের জন্য ব্যবহৃত কাজের ক্ষেত্রে এটি ব্যবহৃত হয়।

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: IIFE এমন একটি function যেটি define করার সাথে সাথেই invoke (call) করা হয়।

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

  1. Compile the code and generate the binary file:
    go build main.go
    
  2. 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:
    1. Text segment: Holds the compiled code of the program.
    2. 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:
    1. Initialized data segment: Holds the initialized global variables and constants.
    2. 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

  1. If the variable is declared inside a function, it will be stored in the stack segment.
  2. If the variable is declared outside a function, it will be stored in the data segment.
  3. If the variable is declared inside a function and it is returned from the function, it will be stored in the heap segment.
  4. 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 compare nil 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.

OperatorExampleSame As
=x = 5x = 5
+=x += 3x = x + 3
-=x -= 3x = x - 3
*=x *= 3x = x * 3
/=x /= 3x = x / 3
%=x %= 3x = 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 and b are parameters of the add function.
  • 5 and 3 are arguments passed to the add function when it is called in the main 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

FeatureNormal VariablePointer
StorageHolds valueHolds memory address
ModificationWorks on copyModifies 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:

  1. Pointers provide direct memory access
  2. Use & to get addresses, * to dereference
  3. Essential for efficient large data handling
  4. 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

  1. 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.
  2. 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.
  3. Can you define multiple receiver functions for the same type?

    • Yes, you can define multiple receiver functions for the same type.
  4. What is the syntax for defining a receiver function?

    • func (receiverType TypeName) methodName(parameters) {}
  5. Can receiver functions be used with built-in types?

    • No, receiver functions can only be defined for user-defined types.
  6. What happens if you call a value receiver function on a pointer?

    • Go automatically dereferences the pointer, so the function works as expected.
  7. What is the purpose of receiver functions?

    • They enable object-oriented programming by associating methods with types.
  8. Can a receiver function modify the original object?

    • Only if it uses a pointer receiver.
  9. 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.
  10. 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:

  1. Package Scope: Variables or functions defined at the package level.
  2. Function Scope: Variables defined within a function.
  3. Block Scope: Variables defined inside a block of code, such as within loops, if-statements, etc.
  4. 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

  1. Variable Shadowing: When a local variable has the same name as a variable in an outer scope, the local variable "shadows" the outer variable.
  2. Exported Variables: Variables that start with an uppercase letter are exported and accessible from other packages. Lowercase variables are private to the package.
  3. 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

  1. 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
    
  2. 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 👇

  1. Using the []datatype{values} format
  2. Create a slice from an array
  3. 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

FeatureArraySlice
SizeFixedDynamic (can grow/shrink)
TypeValue typeReference type
MemoryAll data copied on assignmentJust the slice descriptor copied (shallow copy)
Creationvar a [5]intvar s []int or slicing an array
Common UsageRare (low-level memory control)Very common
PerformanceNo hidden costSome 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 of int values.
  • In the main() function, different sets of arguments are passed to print():
    • 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.

📚 Programming & Golang Resources

এই Category টি Golang এবং জেনারেল প্রোগ্রামিং শেখার জন্য প্রয়োজনীয় লিংক এবং রিসোর্সের সংকলন। এখানে থাকবে ইন্টারনেট জুড়ে ছড়িয়ে থাকা সেরা টিউটোরিয়াল, টুল, ডকুমেন্টেশন, প্র্যাকটিস প্ল্যাটফর্ম এবং আরও অনেক কিছু!


📌 Contents


🧠 Golang Resources

ResourceDescription
Go TourInteractive introduction to Go
Go by ExampleHands-on examples for core Go concepts
Effective GoIdiomatic Go programming practices
GophercisesCoding exercises to improve Go skills
Awesome GoCurated list of Go packages, tools, and resources
Go.dev DocsOfficial documentation and API reference

💡 Programming Essentials

TopicResource
Git & GitHubGit Handbook
Linux CLI BasicsLinux Command Cheat Sheet
CS FoundationsOSSU CS
Operating SystemsOSTEP Book
Algorithms & DSACS50 or AlgoCademy
Regex PlaygroundRegExr

🧰 Useful Tools & Platforms

Tool / PlatformDescription
ReplitOnline IDE with Golang support
Go PlaygroundRun Go code snippets online
StackBlitzFrontend+backend web app prototyping
DevDocsFast documentation browser
CarbonBeautiful code snippet image generator

All competitive programming-related problems and guides have been moved to the warp category.


🚀 Contribution Guide

  • Found a great Golang or dev resource?
    → Open a PR and add it under the right section.

  • Want to organize by difficulty or topic later?
    → Feel free to suggest structure upgrades.


🌐 External Sites

PlatformLink
[Go.dev]https://go.dev
[GitHub]https://github.com
[Stack Overflow]https://stackoverflow.com
[LeetCode]https://leetcode.com
[Codeforces]https://codeforces.com

🚀 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 হয়:

  1. Loader সব .data contents ROM থেকে RAM এ copy করে
  2. এখন RAM এ modification করা যায়
  3. 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:

  1. Law of Separation: "প্রত্যেক type এর variable এর আলাদা district আছে"
  2. Law of Efficiency: "Ghost district file এ কোনো space নেয় না"
  3. 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

[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:
    1. Meters ⇌ Feet
    2. Feet ⇌ Meters
    3. Celsius ⇌ Fahrenheit
    4. Fahrenheit ⇌ Celsius
    5. Kilograms ⇌ Pounds
    6. 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

Documentation for the mini cards project

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

  1. Ensure you have Go installed on your system
  2. Navigate to the project directory:
cd /Users/rokib/Developer/go_projects/bgce-archive/mini-projects/ccwc
  1. 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

  1. Count bytes in a file:
./ccwc -c testdata/test.txt
  1. Count lines in a file:
./ccwc -l testdata/test.txt
  1. Count words in a file:
./ccwc -w testdata/test.txt
  1. Count characters in a file:
./ccwc -m testdata/test.txt
  1. Default output (lines, words, and bytes):
./ccwc testdata/test.txt
  1. 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:

  1. Processor Package (internal/processor/processor.go):

    • Contains core counting functions
    • Implements byte, line, word, and character counting logic
    • Uses efficient buffered I/O operations
  2. 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.

[Author: @hasanmubin Date: 2025-06-19 Category: e.g., mini-projects/GitPulse Tags: [go, GitPulse, mini-projects] ]

GitPulse - A GitHub Activity Tracker CLI 🧑‍💻

A simple command-line tool that fetches and displays the recent public activity of any GitHub user using the GitHub Events API. Built with Go.


🚀 Features

  • Accepts GitHub username as a command-line argument

  • Fetches recent activity from: https://api.github.com/users/<username>/events

  • Displays:

    • Push events (e.g., number of commits pushed to a repo)
    • Issues opened
    • Repositories starred
    • And more...
  • Gracefully handles errors such as:

    • Invalid GitHub usernames
    • Unexpected data formats

📦 Prerequisites

  • Go installed (version 1.18 or above recommended)

🛠️ Setup

  1. Initialize a Go module:

     go mod init GitPulse
    
  2. Build the application:

    go build -o github-activity
    

    This will create a binary file named github-activity.


🧑‍💻 Usage

./github-activity <github-username>

Example:

./github-activity kamranahmedse

Sample Output:

Pushed 3 commits to kamranahmedse/developer-roadmap
Opened a new issue in kamranahmedse/developer-roadmap
Starred kamranahmedse/developer-roadmap

🛯️ Error Handling

  • Invalid username or no recent activity? You’ll get:

    Error: user not found or has no recent public activity.
    
  • Internet down? API fails? You’ll get a meaningful error message instead of a crash.


🌱 Future Improvements (Optional Ideas)

  • Filter by specific event type (PushEvent, IssuesEvent, etc.)
  • Cache results locally to reduce API calls
  • Display output in a more structured or colorized format
  • Explore other endpoints like /repos, /followers, /starred, etc.

🧩 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

✊📄✂️🦎🖖 Rock-Paper-Scissors-Lizard-Spock (Go Edition)

A terminal-based game of Rock, Paper, Scissors, Lizard, Spock — written entirely in Go.
Inspired by The Big Bang Theory and designed to reduce the number of ties from the classic Rock-Paper-Scissors.


🎮 Game Modes

This version supports:

  • Classic Mode: Rock-Paper-Scissors
  • Extended Mode: Rock-Paper-Scissors-Lizard-Spock

The computer picks its move randomly, and you battle it out in the terminal.


🧩 Rules

As explained by Sheldon Cooper:

  • Scissors cuts Paper
  • Paper covers Rock
  • Rock crushes Lizard
  • Lizard poisons Spock
  • Spock smashes Scissors
  • Scissors decapitates Lizard
  • Lizard eats Paper
  • Paper disproves Spock
  • Spock vaporizes Rock
  • Rock crushes Scissors

📸 ASCII Art

Each move comes with its own ASCII art for maximum nerd satisfaction:

Rock:      _______
        ---'   ____)
              (_____)
              (_____)
              (____)
        ---.__(___)

Paper:      _______
        ---'    ____)____
                   ______)
                  _______)
                 _______)
        ---.__________)

…and more for Scissors, Lizard, and Spock.


🚀 How to Run

  1. Clone the repo:

    git clone https://github.com/yourusername/rpsls-go.git
    cd rpsls-go
    
  2. Run the game:

    go run main.go
    

🛠 Features

  • Fully interactive terminal gameplay
  • Input validation (no more typos ruining your match)
  • Fun ASCII art for each move
  • Randomized computer opponent
  • Looping draw condition (keep going until there's a winner)

📌 Example Gameplay

Choose your move:
Rock
    _______
---'   ____)
      (_____)
      (_____)
      (____)
---.__(___)

Paper
     _______
---'    ____)____
           ______)
          _______)
         _______)
---.__________)

... (more ASCII moves) ...

Welcome to the game of Rock, Paper, Scissors, Lizard, Spock
Do you want to read the rules? [y/n]: y

Sheldon explains:
Scissors cuts Paper, Paper covers Rock, Rock crushes Lizard, ...

Enter your move (Rock, Paper, Scissors, Lizard, Spock): Spock
You chose: Spock
Computer chose: Lizard
You lost! Hahaha, you suck!

📜 License

MIT License — feel free to fork, modify, and enjoy.


💡 Credits

  • Inspired by The Big Bang Theory
  • ASCII Art adapted from various open-source snippets

🛰️ BGCE Server (Backend API)

Welcome to the backend server powering the BGCE (Best Golang Community Ever) archive and control system.
This project serves as the foundation for category management, RBAC (Role-Based Access Control), and future API integrations — all written in Golang with simplicity and scalability in mind.


📁 Project Structure

/server
├── main               # Main entry point for the server
├── go.mod             # Go module file (defines module path, dependencies)
│
├── /categories        # Category API handlers
│   ├── categories.go  # HTTP handlers for category management (GET/POST/etc)
│
├── /rbac              # Role-Based Access Control logic
│   ├── superadmin.go  # RBAC logic to allow/disallow actions based on role

🚀 Getting Started

1. Clone the repo & enter the /server directory

git clone https://github.com/yourusername/bgce-archive.git
cd bgce-archive/server

2. Initialize dependencies (if needed)

go mod tidy

3. Run the server

go run main.go

✅ Server runs on: http://localhost:8080


🔐 Role-Based Access Control (RBAC)

For now, Super Admin check is a simple function in rbac/superadmin.go:

func IsSuperAdmin(r *http.Request) bool

This will later be extended using JWT tokens, sessions, or other proper authentication systems.


🧩 API Endpoints (WIP)

EndpointMethodDescriptionAccess
/GETWelcome routePublic
/categoriesGETList all categoriesSuper Admin
/categoriesPOSTCreate a new categorySuper Admin
/categoriesPUTUpdate a categorySuper Admin
/categoriesDELETEDelete a categorySuper Admin

🤝 Contributing

We welcome PRs, ideas, and improvements! Here's how to get started:

  1. Fork the repo
  2. Create a new branch using:
    git switch -c feature/your-feature-name
    
  3. Add your changes (modular, readable, minimal)
  4. If adding route logic, place it under /categories/
  5. If adding role or auth logic, place it under /rbac/
  6. Push and open a PR with a clear title and message

📌 Keep each PR focused — one feature or fix per PR, please!


🔮 Roadmap (WIP Ideas)

  • ✅ Clean route structure using http.ServeMux
  • 🔐 Real token-based Super Admin checks (JWT/session)
  • 📦 Persistent DB (PostgreSQL or SQLite)
  • 🧩 Problem management endpoints
  • 📊 Admin dashboard (frontend)
  • 🔄 JSON response formatting

🧑‍💻 Maintained By

BGCE Mod Team

If you break it, you fix it. If you build it, name it something cool. 😎

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

  1. Clone the repository:
    git clone https://github.com/OxRokib/bgce-archive.git
    
  2. Navigate to the project directory:
    cd bgce-archive/mini-projects/todo-cli
    
  3. 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.

# UDP Server in C

This is a simple UDP server program written in C. It binds to `127.0.0.1` on port `5501` and listens for incoming datagrams.

## Files

- `main.c` : The UDP server code.

## Requirements

- GCC or any C compiler
- Linux or macOS (or WSL on Windows)

## How to Compile and Run

1. **Compile:**

```bash
gcc main.c -o udp_server
  1. Run:
./udp_server

It will start and wait for incoming UDP packets.

Code Explanation (Brief)

  • socket() – creates a UDP socket.
  • bind() – binds to 127.0.0.1:5501.
  • recvfrom() – receives data from any UDP client.
  • printf() – prints the received message.

Example Client (Testing)

To test quickly, use netcat as a UDP client:

echo "Hello Server" | nc -u 127.0.0.1 5501

Or write your own simple C client to send a datagram to port 5501.

Reference

UDP Client-Server Program in C


Notes

  • Change 127.0.0.1 to 0.0.0.0 to bind on all interfaces.
  • Always handle errors in production-grade code (if (sockfd < 0) { perror("socket failed"); exit(1); } etc).

Feel free to modify and extend this as needed for your networking practice or system programming portfolio.

# Simple UDP Server in Node.js

This is a **minimal UDP server** built using Node.js `dgram` module. It listens on `127.0.0.1:41234` and optionally replies back to the client.

## Files

- `server.js` : Contains the UDP server code.

## Requirements

- Node.js (v12+ recommended)
- npm

## How to Run

1. **Install dependencies (if any)**

This script uses only core Node.js modules, so no installation is required. But initialize your project for good practice:

```bash
npm init -y
  1. Run the server
node server.js

You should see:

UDP Server listening on 127.0.0.1:41234

Code Explanation (Brief)

  • dgram.createSocket("udp4") – creates an IPv4 UDP socket.
  • server.on("message") – handles incoming datagrams.
  • server.send() – sends a reply back to the client.
  • server.bind() – binds the server to the specified port and host.

📡 Testing the Server

🔧 Using netcat (nc)

Open a separate terminal and run:

echo "Hello from client" | nc -u 127.0.0.1 41234

You should see the server log the received message and send a reply.

🔧 Using a Node.js UDP client

Create a simple client.js:

import dgram from "dgram";

const client = dgram.createSocket("udp4");
const msg = Buffer.from("Hello server!");

client.send(msg, 0, msg.length, 41234, "127.0.0.1", (err) => {
    if (err) console.error(err);
    else console.log("Message sent!");
    client.close();
});

Run it:

node client.js

Reference


Notes

  • For production use, handle errors and edge cases gracefully.
  • Use udp6 instead of udp4 for IPv6 sockets.
  • Adjust HOST to 0.0.0.0 if you want to accept messages from any network interface.

Happy UDP hacking!

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

  1. Clone the repository:

    git clone https://github.com/0baydullah/UrlShortner-Go.git
    
  2. Navigate to the project directory:

    cd UrlShortner-Go
    
  3. 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
    );
    
  4. 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
    
  5. 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)

App Preview

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.

🧠 কম্পিটিটিভ প্রোগ্রামিং গাইড (CP Guide in Bengali)

📘 এই গাইডটি তৈরি করা হয়েছে বাংলায় CP শেখার সুবিধার্থে। টেকনিক্যাল টার্ম এবং কোড ইংরেজিতে রাখা হয়েছে যাতে ইন্টারন্যাশনাল স্ট্যান্ডার্ড ফলো করা যায়।


🚀 Intro

এই গাইডটি Golang দিয়ে Competitive Programming শেখার জন্য একটি সহজ পথপ্রদর্শক।
আপনি যদি CP-তে নতুন হয়ে থাকেন বা Golang-কে CP-তে ব্যবহার করতে চান, তাহলে এই গাইড আপনার জন্যই! এখানে থাকছে:

  • Easy থেকে Hard লেভেলের categorized problems
  • Bengali explanation সহ curated exercises
  • Community-made contest problems এবং revision list
  • Golang-specific tips & fast I/O templates

🛠️ কিভাবে এই Guide ব্যাবহার করবেন

  1. নিচে থাকা Exercises গুলো থেকে শুরু করুন Golang দিয়ে প্র‍্যাকটিস করতে।
  2. তারপর Problem List অনুযায়ী প্রতিদিন ২-৩টা করে CP Problem solve করুন।
  3. "Tag" দেখে বুঝে নিন কোনটা কোন contest/level এর অংশ।
  4. “UID” ব্যবহার করে solution submit এবং discuss করুন BGCE server এ।
  5. Extra Resource এবং Revision Topics অংশ ব্যাবহার করুন আপনার দক্ষতা বাড়ানোর জন্য।
  6. আমাদের CP সেশনগুলোতে কি কি topic নিয়ে আলোচনা হয়েছে এবং কোন কোন topic আপনি নিজে নিজে practice করবেন তা জানতে Discord CP session log দেখুন।
  7. This is how we are moving forward CP Roadmap

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)
  • Divide into 3 (dncpc7)

পরবর্তীতে আরও exercise add করা হবে।


🧮 Problem List

🔢 Basic Mathematical Problems

#UIDTitleLinkTag
14832Timus 1000Link
27940Timus 1409Link
31602Project Euler 1Link
42314Children and CandiesLinkdncpc1
56851Cloudberry JamsLinkdncpc1
69473RestuarantLinkdncpc1
75119Hashmat the Brave WarriorLink
88640Between Two IntegersLinkdncpc2
91208Domino PilingLinkdncpc2
103765Easy ProblemLinkdncpc3
119021Election Go BrrrLinkdncpc3
121459A Game of ChoiceLinkdncpc3
135184SandglassLinkdncpc3
147804Multiple of 2 and NLinkdncpc4
152691Atocoder CrackersLinkdncpc4
164302Soldier and BananasLinkdncpc4
176789Vasya and SocksLinkdncpc4
189032GardenLinkdncpc5
191025Clock ConversionLinkdncpc5
205671Plus Minus XLinkdncpc6
213421Square YearLinkdncpc7

🧑‍💻 Beginner Friendly CP Problems

#UIDTitleLinkTag
224598Weird AlgorithmLink
237334Concatenation of ArrayLink
241019Sakurako's ExamLink
255640Fifty-FiftyLinkdncpc6
268123Good KidLinkdncpc6
272047Make it BigLinkdncpc6
286831Three DoorsLinkdncpc6
299276Distance TableLinkdncpc7
303915Sushi for TwoLinkdncpc7
310313Ilya and Bank AccountLink
321676Equal CandiesLink
331295Find Numbers with Even Number of digitsLink

🧩 Problems made by the community

পরবর্তীতে আরও প্রব্লেম এবং ক্যাটাগরি যুক্ত করা হবে।


📘 Tips & Resources

Important লিংকস আর রিসোর্স:

আস্তে আস্তে আরও resources যুক্ত করা হবে।


আমাদের যত previous contest

No.Contest typeContest link
1.Dailydncpc1
2.Dailydncpc2
3.Dailydncpc3
4.WeeklyNC001
5.Dailydncpc4
6.Dailydncpc5
7.Dailydncpc6
8.WeeklyNC002

এই গাইডের সাথে থাকুন, নিজের প্রগ্রেস ট্র্যাক করুন, আর শেখা চালিয়ে যান!

Events (full term)

  1. dncpc = Daily (Nebula-Clash) practice contest
  2. NC = Nebula Clash

[Author: @ifrunruhin12 Date: 2025-05-09 Category: docs/warp ]

📅 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 handling
3. .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
সেশন ১৩২০২৫-০৭-০৭1. পূর্ববর্তী CP sessions review
2. পূর্ববর্তী সব টপিক revision
3. CP problem submission guide
popcycle
সেশন ১৪২০২৫-০৭-১৪1.Recursion theory (Firstly show Stack theory)
2.Recursion is one type of bruteforce(Magic)
3.Some basic problems using recursion
4.Basic idea about memoization
MArhamAA

💡 নতুন সেশন যুক্ত হতে থাকবে সময় অনুযায়ী।

📚 CP Session Task

Session No.Session TaskSession Topic
13✅ Solve all problems from cp-guide.mdRevision & Practice
14🔁 Solve the following recursion problems:
Tower of Hanoi (CSES)
Chef and String (CodeChef)
Monster Defeating (AtCoder)
Gray Code (CSES)
Recursion

🛣️ 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 ]