[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 segment | compile করা নির্দেশাবলী এবং constant (a , main , call , Outer , init , show ) |
Data segment | Global variable b |
Stack | Local variable (age ), function call frame |
Heap | Closer ও 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()) │
└──────────────────────────────┘
🧠 ব্যাখ্যা:
a
ওb
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
নামের closurefactor
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)
}
ব্যাখ্যা:
- যদিও
main
এa
পরিবর্তিত হয়েছে, 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
functiona
কে capture করে এবংb
এর সাথে যোগ করে।add5
closurea = 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 দুটি functionf
এবং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 করুন।