Golang রিসিভার ফাংশন
Go-তে কোনো type-এর সাথে ফাংশন attach করার উপায়ই হলো Receiver Function। এটি OOP-এর method-এর সমতুল্য — কিন্তু class ছাড়াই।
🚗 অ্যানালজি: একটি গাড়ির নিজস্ব
Start(),Stop(),Refuel()আছে। Go-তেCarstruct-এর সাথে এই ফাংশনগুলো attach করাই হলো Receiver Function।
১. সাধারণ Function vs Receiver Function
প্রথমে বুঝুন কেন Receiver Function দরকার:
type Car struct {
Brand string
Speed int
}
// ❌ সাধারণ Function — Car-এর সাথে কোনো সম্পর্ক নেই
func StartCar(c Car) {
fmt.Println(c.Brand, "started")
}
// ✅ Receiver Function — Car-এরই নিজস্ব method
func (c Car) Start() {
fmt.Println(c.Brand, "started")
}
// ব্যবহার
car := Car{Brand: "Toyota", Speed: 0}
StartCar(car) // সাধারণ function call
car.Start() // receiver function call — অনেক বেশি readable!কেন ভালো? Receiver function ব্যবহার করলে code অনেক বেশি organized এবং readable হয়।
car.Start()দেখেই বোঝা যায় এটি Car-এর কাজ।
২. Syntax 📌
Receiver function-এর প্রতিটি অংশ:
// ↓ receiver ↓ type ↓ method name ↓ return
func (u User) Greet() string {
return "Hello, " + u.Name // u দিয়ে struct-এর field access করা যায়
}type User struct {
Name string
Age int
}
func (u User) Greet() string { // Value Receiver — read only
return "Hello, " + u.Name
}
func (u *User) Birthday() { // Pointer Receiver — mutates original
u.Age++
}
func main() {
u := User{Name: "Rahim", Age: 25}
fmt.Println(u.Greet()) // "Hello, Rahim"
u.Birthday()
fmt.Println(u.Age) // 26
}৩. Value vs Pointer Receiver 🔥
📄 সহজ অ্যানালজি:
- Value Receiver = ফটোকপি নিয়ে কাজ করা। আসল কাগজে কিছু লেখা হয় না।
- Pointer Receiver = আসল কাগজ নিয়ে কাজ করা। যা লিখবেন তা থেকে যাবে।
| বৈশিষ্ট্য | Value Receiver (u User) | Pointer Receiver (u *User) |
|---|---|---|
| আসল struct পরিবর্তন করে? | ❌ কপিতে কাজ করে | ✅ original-এ কাজ করে |
| মেমোরি ব্যবহার | পুরো struct copy | মাত্র ৪/৮ বাইট (pointer) |
| ব্যবহার | Read-only operation | Mutating operation |
| nil safety | সবসময় safe | nil হলে panic হতে পারে |
| Interface satisfy করে | শুধু T-এর method set | T এবং *T উভয়ের method set |
func (u User) GetAge() int { return u.Age } // Value — safe copy
func (u *User) SetAge(a int) { u.Age = a } // Pointer — modifies original৪. কোনটা কখন ব্যবহার করবেন? (Production Rule) 🔥
Pointer Receiver ব্যবহার করুন —
- struct-এর field পরিবর্তন করতে হলে
- struct বড় হলে (copy cost এড়াতে)
sync.Mutexবা অন্য non-copyable field থাকলে- consistency রাখতে (একটি struct-এ বেশিরভাগ method pointer হলে বাকিগুলোও pointer রাখুন)
Value Receiver ব্যবহার করুন —
- শুধু data read করলে
- struct ছোট এবং immutable হলে (যেমন
time.Time) - primitive type alias-এ (যেমন
type Celsius float64)
⚠️ Golden Rule: একটি struct-এ সব method হয় সবই Value অথবা সবই Pointer receiver রাখুন। Mixed করলে interface satisfaction জটিল হয়।
৫. Method Set ও Interface Satisfaction (Interview Critical) 🔥
🔰 Beginner Note: এই section-টি একটু advanced। প্রথমে §৩ ও §৪ ভালো করে বুঝুন, তারপর এখানে আসুন।
Go-তে কোন receiver type কোন interface satisfy করতে পারে তা নির্ভর করে method set-এর উপর।
সহজ নিয়ম: *T (pointer) সব method call করতে পারে। কিন্তু T (value) শুধু value receiver method-ই call করতে পারে।
| Type | Method Set |
|---|---|
T (value) | শুধু Value Receiver methods |
*T (pointer) | Value Receiver + Pointer Receiver — উভয়ই |
type Stringer interface {
String() string
}
type Point struct{ X, Y int }
func (p *Point) String() string { // Pointer receiver দিয়ে define
return fmt.Sprintf("(%d, %d)", p.X, p.Y)
}
var _ Stringer = &Point{} // ✅ *Point satisfies Stringer
var _ Stringer = Point{} // ❌ compile error — Point does NOT satisfy Stringerকেন?
Point(value)-কে সবসময় address করা যায় না (map value, interface value), তাই Go নিরাপত্তার জন্য value type-এ pointer receiver allow করে না।
৬. Receiver Naming Convention
| Type | Receiver Name |
|---|---|
User | u |
Server | s |
Database | db |
Client | c |
Request | r |
- সর্বদা ১-২ অক্ষর, type-এর abbreviation
selfবাthis— Go-তে anti-pattern, ব্যবহার করবেন না- একটি struct-এ সব receiver-এর নাম একই রাখুন
৭. Production Patterns
Nil Receiver Handling
type Logger struct{ prefix string }
func (l *Logger) Log(msg string) {
if l == nil { // nil check — production must
fmt.Println("[default]", msg)
return
}
fmt.Println("["+l.prefix+"]", msg)
}
var l *Logger
l.Log("server started") // ✅ panic নেই — "default" print হবেMethod Chaining — Builder Pattern
type QueryBuilder struct {
table string
limit int
offset int
}
func (q *QueryBuilder) Table(t string) *QueryBuilder { q.table = t; return q }
func (q *QueryBuilder) Limit(n int) *QueryBuilder { q.limit = n; return q }
func (q *QueryBuilder) Offset(n int) *QueryBuilder { q.offset = n; return q }
// Usage
q := (&QueryBuilder{}).Table("users").Limit(10).Offset(0)fmt.Stringer — সবচেয়ে বেশি ব্যবহৃত Interface
type Status int
const (
Active Status = iota
Inactive
Banned
)
func (s Status) String() string {
return [...]string{"Active", "Inactive", "Banned"}[s]
}
fmt.Println(Active) // "Active" — fmt স্বয়ংক্রিয়ভাবে String() call করে
fmt.Println(Banned) // "Banned"error Interface Implementation
type AppError struct {
Code int
Message string
}
func (e *AppError) Error() string {
return fmt.Sprintf("error %d: %s", e.Code, e.Message)
}
// Usage
func GetUser(id int) (*User, error) {
if id <= 0 {
return nil, &AppError{Code: 400, Message: "invalid id"}
}
return &User{}, nil
}৮. Common Mistakes ⚠️
| ভুল | সমস্যা | সমাধান |
|---|---|---|
| Value receiver-এ field পরিবর্তন | copy-তে change হয়, original অপরিবর্তিত | Pointer receiver ব্যবহার করুন |
| Mixed receiver types একই struct-এ | method set জটিল, interface satisfy কঠিন | সব method-এ একই receiver type রাখুন |
| nil pointer-এ unchecked method call | runtime panic | Pointer receiver-এ nil guard রাখুন |
| বড় struct-এ value receiver | প্রতি call-এ ব্যয়বহুল copy | Pointer receiver ব্যবহার করুন |
self / this receiver name | Go idiom বিরোধী, code review-এ reject | ছোট abbreviation ব্যবহার করুন |
৯. Interview Cheat Sheet
Q: Value vs Pointer Receiver-এর মূল পার্থক্য?
Value receiver struct-এর copy-তে কাজ করে (read-only)। Pointer receiver original struct-এ কাজ করে (read + write)।
Q: কখন Pointer Receiver বাধ্যতামূলক?
১. struct modify করতে হলে। ২.
sync.Mutexবা non-copyable type থাকলে। ৩. বড় struct-এ performance-এর জন্য।
Q: T এবং *T-এর method set কেন আলাদা?
Value
T-কে সবসময় address করা যায় না (map value, interface value), তাই Go নিরাপত্তার জন্য value type-এ pointer receiver method রাখে না।
Q: Interface satisfaction-এ receiver type কীভাবে প্রভাব ফেলে?
Pointer receiver দিয়ে method define করলে শুধু
*Tসেই interface satisfy করে,Tনয়।
Q: Nil receiver-এ method call কি valid?
হ্যাঁ — Go panic করে না যদি method-এর ভেতরে nil check থাকে। এটি একটি valid production pattern।
Q: একই struct-এ value ও pointer receiver mix করা যাবে?
Syntactically যাবে, কিন্তু করা উচিত নয়। Interface satisfaction-এ বিভ্রান্তি তৈরি হয় এবং Go team এটি discourage করে।
🧠 মনে রাখার কৌশল
| মনে রাখুন | মানে |
|---|---|
| Value = View only | শুধু দেখার জন্য, পরিবর্তন নয় |
| Pointer = Permission to change | পরিবর্তনের অনুমতি আছে |
(t T) → “একটি কপি নাও” | আসল অপরিবর্তিত |
(t *T) → “আসলটাই নাও” | আসল পরিবর্তন হবে |