چطور و چه وقت از Pointerها (اشارهگرها) در Go استفاده کنیم
سه شنبه 20 آبان 1399زبان برنامهنویسی Go در سالهای اخیر محبوبیت زیادی به دست آورده است. این زبان به طور مداوم سایر زبانهای backend مثل Ruby، Python، Java و C# را جا به جا میکند. Go به دلیل سادگی، صراحت، سرعت و مصرف کم حافظه خواهان زیادی دارد.
بسیاری از توسعهدهندگان که تازهکار هستند، یا در زبانی که میتواند حافظه را به طور مستقیم با استفاده از اشارهگرها یا همان پوینترها مدیریت کند تازهکار هستند، در نهایت از این اشارهگرها به شکل بدی استفاده میکنند.
پوینتر چیست؟
پوینتر متغیری است که آدرس مقدار را به جای خود مقدار ذخیره میکند. اگر حافظه کامپیوتر (RAM) را به عنوان شیء JSON در نظر بگیرید، یک پوینتر مانند کلید است، و یک متغیر معمولی مقدار آن است.
{
"pointer": "variableValue"
}
بیایید یک مورد را در عمل ببینیم:
package main
import "fmt"
func main() {
// create a normal string variable
name := "original"
// pass in a pointer to the string variable using '&'
setName(&name, "qvault")
fmt.Println(name)
}
func setName(ptr *string, newName string) {
// dereference the pointer so we can modify the value
// and set the value to "qvault"
*ptr = newName
}
این چاپ میشود:
qvault
همانطور که میبینید، از آنجایی که ما یک پوینتر برای آدرس متغیر داریم، میتوانیم مقدار آن را تغییر دهیم، حتی در محدوده تابع دیگری. اگر مقدار پوینتر نبود، این کار نمیکرد:
package main
import "fmt"
func main() {
name := "original"
setNameBroken(name, "qvault")
fmt.Println(name)
}
func setNameBroken(ptr string, newName string) {
ptr = newName
}
چاپ:
original
پوینترها میتوانند سودمند باشند، اما به همان اندازه که مفید هستند میتوانند خطرناک باشند. مثلا، اگر از پوینتری استفاده کنیم که هیچ مقداری ندارد، برنامه دچار مشکل میشود. به همین دلیل ما همیشه قبل از تلاش برای چاپ کردن، چک میکنیم ببینیم آیا مقدار خطاNil است.
سینتکس
1. ساخت پوینتر: &
newString := ""
newStringPointer := &newString
اگر این پوینتر را چاپ کنید، یک آدرس حافظه خواهید دید.
package main
import "fmt"
func main() {
newString := ""
newStringPointer := &newString
fmt.Println(newStringPointer)
}
prints: 0xc00000e1e0
آدرس حافظه این متغیر در دستگاه شما چیست؟
2. توصیف پوینتر: *
در signature ی تابع یا تعریف نوع، * برای این استفاده میشود که مشخص کند مقدار، یک پوینتر است.
func passPointer(pointer *string) {
}
3. ارجاع پوینتر (Dereferencing): *
ممکن است کمی گیجکننده باشد، اما * که برای توصیف پوینتر استفاده میشد همچنین به عنوان عملگری برای ارجاع به مقدار حافظهای که داخل پوینتر است نیز استفاده میشود.
func derefPointer(pointer *string) {
newStringVariable := *pointer
// newStringVariable is just a normal string
}
چه وقت باید از پوینتر استفاده کنیم؟
احتمالا موارد ظریف بسیاری برای وقتی که پوینتر یک ایده خوبی است وجود دارد. اما ما حدس میزنیم که 95% زمانهایی که از پوینتر استفاده میکنید، باید به دلیل یکی از موارد زیر باشد:
1. تابعی که یکی از پارامترهای خود را تغییر میدهد
وقتی تابعی را فراخوانی میکنیم که یک پوینتر را به عنوان پارامتر میگیرد، انتظار داریم که متغیر ما تغییر داده شود. اگر شما متغیر را در تابع خود تغییر نمیدهید، پس احتمالا نباید از پوینتر استفاده کنید.
2. عملکرد بهتر
اگر رشتهای داشته باشید که شامل یک رمان کامل در حافظه باشد، کپی کردن این متغیر هر بار که به یک تابع جدید ارسال میشود، کاری بسیار گران است. ممکن است ارزشمند باشد که به جای این کار یک پوینتر را ارسال کنید، که باعث صرفهجویی در پردازنده و حافظه میشود. با این حال انجام این کار به قمیت خوانا بودن است، بنابراین فقط در صورت لزوم این بهینهسازی را انجام دهید.
3. به گزینه Nil نیاز دارید
گاهی اوقات یک تابع باید بداند که مقدار یک چیزی چیست، همچنین باید وجود یا عدم وجود آن را بداند. معمولا هنگام خواندن JSON از این استفاده میکنیم تا بدانیم فیلدی وجود دارد یا خیر. مثلا اگر یک شیء JSON باشد:
{ "name": "qvault" } ----> *name: "qvault"
{ "name": "" } ----------> *name: ""
{} ----------------------> *name: nil
جمعبندی
اینها برخی از موارد کلی برای استفاده از پوینترها در کدتان است. اگر مطمئن نیستید و مقدار معمولی به خوبی کار میکند، توصیه میکنیم از پوینتر استفاده نکنید. یوینترها ابزار مفیدی هستند اما به راحتی میتوانند منجر به اشکالات ناخوشایند یا کد غیر قابل خواندن شوند.
در صورتی که به این زبان محبوب و آیندهدار علاقهمند هستید، میتوانید برای شروع از آموزش رایگان زبان GO از صفر شروع کنید، و سپس برای پیشرفته شدن از آموزش زبان برنامهنویسی GO استفاده کنید.
- برنامه نویسان
- 2k بازدید
- 0 تشکر