🔹 مفاهیم پایه و داخلی 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) میشناسی؟
✅ جواب:
- متغیرها رو توی stack ذخیره کنیم نه heap (چون جمعآوری حافظه توی heap گرونه!)
- از object pool استفاده کنیم تا اشیای تکراری رو دوباره مصرف کنیم.
- از تخصیص زیاد slice و map پرهیز کنیم.
- تعداد زیاد 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 رو شناسایی کنیم؟
✅ جواب:
-
از
pprof
استفاده کن:go run main.go
go tool pprof http://localhost:8080/debug/pprof/heap -
از
runtime.ReadMemStats
برای مانیتورینگ حافظه استفاده کن. -
استفاده از ابزار
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 explicitif-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