آموزش اشارهگر در گولنگ - راهنمای کامل Pointer در Go
2025/11/24
اشارهگر (Pointer) متغیری است که آدرس حافظه یک متغیر دیگر را ذخیره میکند. درک pointerها برای نوشتن کد کارآمد در Go ضروری است.
چرا Pointer؟
کارایی: به جای کپی کردن داده بزرگ، فقط آدرس را پاس میدهیم
تغییر مقدار: امکان تغییر متغیر اصلی در تابع
اشتراک داده: چند بخش برنامه به یک داده دسترسی دارند
سینتکس پایه
packagemainimport"fmt"funcmain(){x:=42// دریافت آدرس با &ptr:=&xfmt.Println("مقدار x:",x)// 42fmt.Println("آدرس x:",&x)// 0xc0000140a0fmt.Println("مقدار ptr:",ptr)// 0xc0000140a0fmt.Println("مقدار در آدرس:",*ptr)// 42 (dereference)}
عملگرها
عملگر
نام
کاربرد
&
Address-of
دریافت آدرس متغیر
*
Dereference
دسترسی به مقدار در آدرس
تعریف Pointer
packagemainimport"fmt"funcmain(){// روش 1: تعریف و مقداردهیvarxint=10varptr*int=&x// روش 2: استنتاج نوعy:=20ptr2:=&y// روش 3: pointer به structtypePersonstruct{NamestringAgeint}p:=Person{Name:"علی",Age:25}pPtr:=&pfmt.Printf("ptr: %T, value: %v\n",ptr,*ptr)fmt.Printf("ptr2: %T, value: %v\n",ptr2,*ptr2)fmt.Printf("pPtr: %T, name: %v\n",pPtr,pPtr.Name)}
nil Pointer
Pointer بدون مقداردهی nil است:
varptr*int// nilifptr==nil{fmt.Println("Pointer خالی است")}// دسترسی به nil pointer باعث panic میشود!// fmt.Println(*ptr) // panic: runtime error
تغییر مقدار با Pointer
packagemainimport"fmt"funcmain(){x:=10ptr:=&x// تغییر مقدار از طریق pointer*ptr=20fmt.Println("x:",x)// 20 (تغییر کرد!)}
Pointer در توابع
بدون Pointer (کپی مقدار)
funcdouble(xint){x=x*2// فقط کپی تغییر میکند}funcmain(){num:=5double(num)fmt.Println(num)// 5 (تغییر نکرد!)}
با Pointer (تغییر مقدار اصلی)
funcdouble(x*int){*x=*x*2// مقدار اصلی تغییر میکند}funcmain(){num:=5double(&num)fmt.Println(num)// 10 (تغییر کرد!)}
برگرداندن Pointer
funcnewInt(xint)*int{return&x// در Go این امن است (escape analysis)}funcmain(){ptr:=newInt(42)fmt.Println(*ptr)// 42}
Pointer به Struct
packagemainimport"fmt"typeUserstruct{NamestringEmailstringAgeint}// با pointer - میتواند تغییر دهدfunc(u*User)SetAge(ageint){u.Age=age}// بدون pointer - فقط خواندنfunc(uUser)GetInfo()string{returnfmt.Sprintf("%s (%d)",u.Name,u.Age)}funcmain(){user:=User{Name:"علی",Email:"ali@example.com",Age:25}// Go خودکار & و * را مدیریت میکندuser.SetAge(30)// معادل (&user).SetAge(30)fmt.Println(user.GetInfo())// علی (30)// کار با pointeruserPtr:=&useruserPtr.Name="رضا"// معادل (*userPtr).Namefmt.Println(user.Name)// رضا}
new و make
new - تخصیص حافظه و برگرداندن pointer
// new یک pointer به مقدار صفر برمیگرداندptr:=new(int)// *int با مقدار 0fmt.Println(*ptr)// 0*ptr=42fmt.Println(*ptr)// 42// معادل:varxintptr2:=&x
make - برای slice، map، channel
// make مقدار واقعی برمیگرداند (نه pointer)slice:=make([]int,5)// []intm:=make(map[string]int)// map[string]intch:=make(chanint)// chan int
typeCounterstruct{countint}// Value receiver - کپی میشودfunc(cCounter)ValueIncrement(){c.count++// فقط کپی تغییر میکند}// Pointer receiver - اصل تغییر میکندfunc(c*Counter)PointerIncrement(){c.count++}funcmain(){counter:=Counter{count:0}counter.ValueIncrement()fmt.Println(counter.count)// 0counter.PointerIncrement()fmt.Println(counter.count)// 1}
کی از کدام استفاده کنیم؟
استفاده از Pointer Receiver
استفاده از Value Receiver
وقتی میخواهید تغییر دهید
وقتی فقط میخوانید
struct بزرگ است
struct کوچک است
consistency با متدهای دیگر
نوعهای پایه مثل int
نکات مهم
۱. Go آدرس stack را مدیریت میکند
// این در Go امن است (بر خلاف C)funccreateInt()*int{x:=42return&x// Go به heap منتقل میکند}
۲. Pointer arithmetic نداریم
// این در Go کار نمیکند:// ptr++// ptr + 1
۳. همیشه nil را بررسی کنید
funcprocess(ptr*int){ifptr==nil{return}// کار با *ptr}