پرش به مطلب اصلی

🔹 مفاهیم پایه و داخلی Go

1. چرا در Go از پکیج‌ها استفاده می‌کنیم؟

✅ جواب: پکیج‌ها کمک می‌کنن که کدمون مرتب‌تر و ماژولار باشه، یعنی بخش‌های مختلف برنامه رو جدا کنیم که راحت‌تر مدیریت بشه. همچنین باعث میشه که کد قابل استفاده مجدد (reusable) باشه.


2. هدف از init() در Go چیه؟

✅ جواب: این یه فانکشن خاص توی هر پکیجه که قبل از main() اجرا میشه و معمولاً برای مقداردهی اولیه (initialization) استفاده میشه.

package main
import "fmt"

func init() {
fmt.Println("قبل از main اجرا میشم!")
}

func main() {
fmt.Println("این main هستش")
}

🔹 خروجی:

قبل از main اجرا میشم!
این main هستش

3. چجوری کامپایلر Go موقع اجرا بهینه‌سازی می‌کنه؟

✅ جواب: کامپایلر یه سری بهینه‌سازی انجام میده تا کد سریع‌تر اجرا بشه، مثل:

  • اInlining (بردن کد تابع‌های کوچیک داخل بدنه‌ی کد)
  • حذف کدهای بی‌استفاده (Dead Code Elimination)
  • جایگذاری مقدار ثابت‌ها (Constant Propagation)
  • ا (Escape Analysis)
const x = 10
y := x + 5 // اینو مستقیماً تبدیل میکنه به:
y := 15

4. چه تکنیک‌هایی برای کاهش فشار Garbage Collector (GC) می‌شناسی؟

✅ جواب:

  1. متغیرها رو توی stack ذخیره کنیم نه heap (چون جمع‌آوری حافظه توی heap گرونه!)
  2. از object pool استفاده کنیم تا اشیای تکراری رو دوباره مصرف کنیم.
  3. از تخصیص زیاد slice و map پرهیز کنیم.
  4. تعداد زیاد goroutine نسازیم چون هر کدوم حافظه مصرف می‌کنن.

5. پکیج unsafe چیه و کِی استفاده میشه؟

✅ جواب: این پکیج به ما اجازه میده که به حافظه مستقیم دسترسی داشته باشیم و نوع متغیرها رو به شکل دلخواه تغییر بدیم. ولی چون باعث ناامنی حافظه و crash شدن برنامه میشه، فقط وقتی لازمه ازش استفاده می‌کنیم، مثلاً برای بهینه‌سازی سطح پایین.


6. اdefer در Go چیه و چطور اجرا میشه؟

✅ جواب:

  • اdefer یه فانکشنیه که بعد از خروج از تابع اجرا میشه.
  • برای پاک‌سازی منابع (مثل بستن فایل یا اتصال به دیتابیس) خیلی به کار میاد.
  • اگه چندتا defer داشته باشیم، برعکس ترتیب تعریف‌شدن اجرا میشن (LIFO).
func main() {
defer fmt.Println("اول defer")
defer fmt.Println("دوم defer")
fmt.Println("Hello")
}

🔹 خروجی:

Hello
دوم defer
اول defer

7. اstruct چیه و چرا مهمه؟

✅ جواب: یه نوع داده‌ای که چند مقدار مرتبط رو توی یک جا ذخیره می‌کنه. مثلاً:

type Person struct {
Name string
Age int
}

اگه یه struct رو بدون اشاره‌گر به یه تابع بفرستیم، مقدارش تغییر نمی‌کنه چون Go مقدار رو کپی می‌کنه.


8. چطور string رو به rune تبدیل کنیم؟

✅ جواب:

runes := []rune("سلام")
fmt.Println(runes) // [1587 1604 1575 1605]

چون rune یه int32 هست، هر کاراکتر رو تبدیل به عدد یونیکدش میکنه.


🔹 سیستم و تعامل با OS

9. چطور یه کامند مثل ls رو از برنامه اجرا کنیم؟

✅ جواب:

cmd := exec.Command("ls", "-la")
output, _ := cmd.Output()
fmt.Println(string(output))

این کد خروجی ls -la رو چاپ می‌کنه. بهتره که دستورات یوزر رو مستقیم اجرا نکنیم تا جلوی حملات command injectionی رو بگیریم


10. اsyscall چیه و چرا دیگه ازش استفاده نمیشه؟

✅ جواب: پکیج syscall برای دستورات سطح پایین سیستم‌عامله ولی دیگه قدیمیه! الان از پکیج x/sys/unix استفاده می‌کنیم که کراس‌پلتفرمه.


11. چطور کاربر فعلی سیستم‌عامل رو در Go بگیریم؟

✅ جواب:

import "os/user"
u, _ := user.Current()
fmt.Println(u.Username)

12. چطور یه وب سرور ساده توی Go اجرا کنیم؟

✅ جواب:

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 
w.Write([]byte("Hello, World!"))
})
http.ListenAndServe(":8080", nil)

🔹 امنیت و مدیریت داده

13. چطور جلوی SQL Injection رو بگیریم؟

✅ جواب: به جای fmt.Sprintf از ? توی کوئری‌ها استفاده کن!

db.Query("SELECT * FROM users WHERE username = ?", username)

چون اینجوری دیتابیس مقدار ورودی رو فرمت می‌کنه و حمله‌های SQL Injection بی‌اثر میشن.


14. چطور JWT Auth رو به‌صورت ایمن پیاده کنیم؟

✅ جواب:

  • همیشه JWT رو درون Authorization هدر بفرستید. و same site و secure رو فعال کنید روش
  • از secret key قوی برای امضای JWT استفاده کنید.
  • تاریخ انقضا (expiration time) رو تنظیم کنید.

🔹 کانکارنسی در Go

15. چه فرقی بین channel و mutex هست؟

✅ جواب:

  • اchannel برای ارسال و دریافت داده بین goroutineها مناسبه.
  • اmutex برای قفل کردن متغیرهای مشترک و جلوگیری از race condition استفاده میشه.

16. اWaitGroup چیه و چه فرقی با channel داره؟

✅ جواب:

  • اWaitGroup صبر می‌کنه تا همه goroutineها تموم بشن ولی داده جابه‌جا نمی‌کنه.
  • اchannel هم برای سینک کردن goroutineها استفاده میشه، هم برای انتقال داده.

17. چطور goroutine leak رو پیدا و برطرف کنیم؟

✅ جواب:

  • همیشه با select بررسی کن که goroutine تموم شده یا نه.
  • قبل از return، کانال‌ها رو ببند (close()) تا گیر نکنن.

18. چطور تعداد goroutineهای همزمان رو محدود کنیم؟

✅ جواب: با یه channel به‌عنوان سمفور:

limit := make(chan struct{}, 5) // فقط ۵ goroutine همزمان
for i := 0; i < 10; i++ {
go func() {
limit <- struct{}{} // گرفتن اسلات
defer func() { <-limit }() // آزاد کردن اسلات
}()
}

🔹 مدیریت حافظه و بهینه‌سازی در Go

19. چطور جلوی memory leak در Go رو بگیریم؟

✅ جواب:

  • همیشه کانال‌ها رو بعد از استفاده ببند (close(ch)).
  • برای goroutineها کانتکست (context.WithCancel) بذار تا بعد از استفاده متوقف بشن.
  • از sync.Pool برای ذخیره‌سازی اشیای پرتکرار استفاده کن.

20. چطور memory leak رو شناسایی کنیم؟

✅ جواب:

  1. از pprof استفاده کن:

    go run main.go
    go tool pprof http://localhost:8080/debug/pprof/heap
  2. از runtime.ReadMemStats برای مانیتورینگ حافظه استفاده کن.

  3. استفاده از ابزار memtrace و trace برای تحلیل مصرف رم.

package main 
import ( "fmt" "runtime" )
func printMemUsage() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("Memory Usage: %v MB\n", m.Alloc/1024/1024)
}

func main() {
printMemUsage() // قبل از اجرای عملیات
_ = make([]byte, 50<<20) // تخصیص 50 مگابایت حافظه
printMemUsage() // بعد از تخصیص

🔹 کانکارنسی در Go

21. در چه مواقعی باید از channel و چه مواقعی از mutex استفاده کرد؟

✅ جواب:

  • وقتی که داده رو بین goroutineها جابه‌جا می‌کنی، از channel استفاده کن.
  • وقتی فقط می‌خوای یک متغیر رو بین چند goroutine قفل کنی، از mutex استفاده کن.

22. فرق slice و array در Go چیه؟

✅ جواب:

  • ا**array طولش ثابت و غیرقابل تغییره**.
  • اslice داینامیکه و میشه طولش رو تغییر داد.
arr := [3]int{1, 2, 3}  // آرایه با طول ثابت
slc := []int{1, 2, 3} // اسلایس داینامیک

23. کی باید از channel و کی از mutex استفاده کنیم؟

✅ جواب:

  • اگه قراره داده بین چند goroutine جابه‌جا بشه → از channel استفاده کن.
  • اگه قراره چند goroutine همزمان به یه متغیر دسترسی داشته باشن → از mutex استفاده کن.

24. کی باید از channel و کی از WaitGroup استفاده کنیم؟

✅ جواب:

  • ا**WaitGroup فقط صبر می‌کنه goroutineها تموم بشن، ولی داده جابه‌جا نمی‌کنه!**
  • اchannel هم می‌تونه goroutineها رو سینک کنه، هم می‌تونه داده انتقال بده.
var wg sync.WaitGroup
wg.Add(2)

go func() { fmt.Println("Task 1"); wg.Done() }()
go func() { fmt.Println("Task 2"); wg.Done() }()

wg.Wait()

25. تفاوت buffered و unbuffered channel چیه؟

✅ جواب:

  • اunbuffered channel بلاک میشه تا گیرنده بیاد دیتا رو برداره.
  • اbuffered channel تا جایی که ظرفیت داره، بلاک نمیشه.
ch := make(chan int) // بلاک میشه تا داده دریافت بشه
bufCh := make(chan int, 3) // می‌تونه ۳ مقدار رو بدون بلاک شدن نگه داره

🔹 امنیت در Go

26. چطور از SQL Injection جلوگیری کنیم؟

✅ جواب:

  • از جایگذاری پارامتر (?) در کوئری‌ها استفاده کن، نه fmt.Sprintf!
  • هیچ‌وقت ورودی کاربر رو مستقیم توی SQL قرار نده.
db.Query("SELECT * FROM users WHERE username = ?", username)

27. چطور JWT Auth رو به‌صورت ایمن پیاده کنیم؟

✅ جواب:

  • اJWT باید Expiration Time داشته باشه.** و هدر ها رو به صورت secure and same site
  • حتماً از HMAC-SHA256 یا RSA برای امضای JWT استفاده کن.
  • کلید (secret key) نباید توی کد ذخیره بشه!

🔹 مدیریت منابع و پرفورمنس در Go

28. چطور تعداد goroutineها رو کنترل کنیم؟

✅ جواب:
با استفاده از یک کانال به عنوان سمفور، می‌تونیم تعداد goroutineهای همزمان رو کنترل کنیم:

sem := make(chan struct{}, 5) // حداکثر ۵ goroutine همزمان

for i := 0; i < 10; i++ {
go func() {
sem <- struct{}{} // گرفتن ظرفیت
fmt.Println("Running goroutine")
<-sem // آزاد کردن ظرفیت
}()
}

29. چطور در Go worker pool بسازیم؟

✅ جواب:

jobs := make(chan int, 10)
results := make(chan int, 10)

for w := 1; w <= 3; w++ { // ۳ تا worker
go func() {
for job := range jobs {
results <- job * 2
}
}()
}

ا30. sync.Mutex و sync.RWMutex چه فرقی دارن؟

✅ جواب:

  • اsync.Mutex کل دسترسی رو قفل می‌کنه.
  • اsync.RWMutex به خواننده‌ها (RLock()) اجازه میده که همزمان بخونن، ولی فقط یه نویسنده (Lock()) می‌تونه بنویسه.
var mu sync.RWMutex
mu.RLock() // خواندن داده بدون بلاک کردن بقیه خواننده‌ها
mu.RUnlock()

🔹 پردازش هم‌زمان و بهینه‌سازی

ا31. select در Go چه کاری انجام میده؟

✅ جواب:
select اجازه میده که همزمان چندین channel رو گوش کنیم و هرکدوم آماده بود، اجرا بشه.

select {
case msg := <-ch1:
fmt.Println("داده از ch1:", msg)
case msg := <-ch2:
fmt.Println("داده از ch2:", msg)
}

32. چطور از context.WithTimeout برای زمان‌بندی استفاده کنیم؟

✅ جواب:

ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

select {
case <-time.After(3 * time.Second):
fmt.Println("Done")
case <-ctx.Done():
fmt.Println("Timeout!")
}

33. چطور اجرای درخواست‌های HTTP رو در Go محدود کنیم؟

✅ جواب:
از rate limiter استفاده می‌کنیم:

limiter := time.Tick(200 * time.Millisecond)

for req := range requests {
<-limiter // محدود کردن درخواست‌ها
fmt.Println("Processing request", req)
}

34. چطور از حملات Directory Traversal در Go جلوگیری کنیم؟

✅ جواب:

  • همیشه مسیرها رو با filepath.Clean() پاک‌سازی کن.
  • دسترسی‌های فایل رو محدود کن.

35. چطور TLS رو روی Go HTTP سرور فعال کنیم؟

✅ جواب:

http.ListenAndServeTLS(":443", "cert.pem", "key.pem", nil)

🔹 کانکارنسی و سینک کردن Goroutineها

36. چرا توی Go starvation اتفاق نمیفته؟

✅ جواب:

  • اGo یه scheduler داخلی داره که به همه‌ی goroutineها فرصت اجرا میده.
  • برخلاف قفل‌های سخت مثل mutex، استفاده از channel باعث میشه هیچ goroutineای گیر نکنه.
  • اگه یه goroutine خیلی سنگین بشه، Go با preemptive scheduling اون رو متوقف می‌کنه و به بقیه فرصت اجرا میده.

37. چطور یه goroutine رو متوقف کنیم؟

✅ جواب:

  • استفاده از context.WithCancel برای متوقف کردن goroutine:
ctx, cancel := context.WithCancel(context.Background())

go func() {
for {
select {
case <-ctx.Done():
fmt.Println("Stopping goroutine...")
return
default:
fmt.Println("Running...")
time.Sleep(500 * time.Millisecond)
}
}
}()

time.Sleep(2 * time.Second)
cancel() // goroutine رو متوقف می‌کنه

38. چطور یه goroutine رو زمان‌بندی کنیم که بعد از یه مدت تموم بشه؟

✅ جواب:

  • استفاده از context.WithTimeout:
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

go func() {
<-ctx.Done() // بعد از ۲ ثانیه متوقف میشه
fmt.Println("Goroutine timeout!")
}()

39. چطور چندین goroutine رو همزمان اجرا کنیم و وقتی همه تموم شدن ادامه بدیم؟

✅ جواب:

  • استفاده از sync.WaitGroup:
var wg sync.WaitGroup

for i := 0; i < 3; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
fmt.Println("Goroutine", i, "finished")
}(i)
}

wg.Wait() // صبر می‌کنه تا همه‌ی goroutineها تموم بشن

40. چطور چندین کانال رو به یک خروجی مشترک ترکیب کنیم (fan-in pattern)؟

✅ جواب:

  • ا**fan-in** یعنی چند کانال رو بگیریم و خروجیشون رو توی یه کانال ادغام کنیم.
func merge(ch1, ch2 <-chan int) <-chan int {
out := make(chan int)
go func() {
for val := range ch1 {
out <- val
}
}()
go func() {
for val := range ch2 {
out <- val
}
}()
return out
}

ch1 := make(chan int)
ch2 := make(chan int)

go func() { ch1 <- 1; close(ch1) }()
go func() { ch2 <- 2; close(ch2) }()

out := merge(ch1, ch2)

for val := range out {
fmt.Println(val)
}

🔹 خروجی:

1
2

نکات جالب

  • Go has only one loop type: for.
  • Arrays in Go are fixed size, whereas slices are dynamic.
  • Strings in Go are immutable.
  • Structs can have tags (json:"name") for metadata.
  • The container/list package implements linked lists.
  • The container/ring package creates circular lists.
  • os.ReadDir(".") lists directory contents.
  • Goroutines are lightweight threads managed by Go’s runtime.
  • Channels provide safe communication between goroutines.
  • Go's garbage collector uses tricolor mark-and-sweep for memory management.
  • The sync.WaitGroup helps synchronize multiple goroutines.
  • The select statement allows listening to multiple channels simultaneously.
  • defer statements execute in LIFO order (Last-In-First-Out).
  • Go doesn’t support implicit type conversions between numeric types.
  • The iota keyword simplifies defining incrementing constants.
  • The math/big package enables arbitrary precision calculations.
  • Go doesn’t have inheritance, but supports composition via struct embedding.
  • Methods in Go can have pointer receivers to modify struct values.
  • The context package helps manage timeouts and cancellations in goroutines.
  • Maps (map[key]value) provide constant-time lookups (O(1)) in average cases.
  • Go has no exceptions, only error handling via multiple return values.
  • The os/exec package allows executing external system commands.
  • The sync.Mutex is used to prevent race conditions in concurrent programs.
  • GOMAXPROCS controls the number of OS threads Go uses for execution.
  • The testing package is built-in for unit testing in Go.
  • Go doesn’t have ternary operators (? :), and encourages explicit if-else statements.
  • The net/http package provides a fully functional HTTP client and server.
  • recover() can catch panics and prevent a program from crashing.
  • The reflect package enables runtime type inspection, though it’s slower than static typing.
  • Go binaries are statically linked, meaning they don’t require additional dependencies at runtime.
  • strings are immutable in go