Go Pointers در مقابل ارزش ها: چه موقع از آنها استفاده کنید (و چه موقع نیست)

اگر تازه وارد شوید ، یک مورد که به سرعت متوجه خواهید شد این است که Go ندارد null
مانند برخی از زبانهای دیگر – این دارد مقادیر صفر در عوض اما اگر شما نیاز به تفاوت بین زمینه ای که هرگز تنظیم نشده است و یکی از مواردی که صریحاً روی صفر تنظیم شده است ، چه می کنید؟ اینجاست نشانگرها می تواند کمک کند – اما آنها همچنین می توانند پیچیدگی غیر ضروری را معرفی کنند. بیایید قدم به قدم آن را بشکنیم.
مشکل: از دست رفته در مقابل صفر
تصور کنید که با داده های JSON کار می کنید که نمایانگر یک کاربر است:
{ "name": "" }
در مقابل
{}
اگر ساختار GO خود را مانند این تعریف کنیم:
type User struct {
Name string `json:"name"`
}
هر دو نمونه JSON در بالا منجر به user.Name == ""
در برو این بدان معنی است که ما نمی توانیم بگوییم که آیا این نام وجود دارد:
- عمداً تنظیم شده است به یک رشته خالی
- هرگز شامل نمی شود اصلاً در JSON.
اگر مقادیر از دست رفته نیاز به دست زدن به ویژه داشته باشند ، این می تواند یک مشکل باشد.
راه حل: استفاده از نشانگرها برای JSON
type User struct {
Name *string `json:"name"`
}
اکنون ، ما می توانیم بررسی کنیم که آیا Name
است ، nil
:
func main() {
jsonData := `{}` // No "name" field
var user User
json.Unmarshal([]byte(jsonData), &user)
if user.Name == nil {
fmt.Println("Name is missing")
} else {
fmt.Println("Name is:", *user.Name)
}
}
اینجا چه اتفاقی می افتد؟
-
اگر
name
زمینه در JSON وجود ندارد ،user.Name == nil
بشر -
اگر
name
زمینه وجود دارد اما خالی است ("name": ""
)user.Name
است ، نه صفر، اما مقدار آن است""
بشر
این کار هنگام کار با API ، پایگاه داده یا تنظیماتی که در آن مقدار از دست رفته با یک خالی متفاوت است ، مفید است.
هنگام استفاده از نشانگرها
نشانگرها می توانند باشند بیش از حد، خواندن کد سخت تر و مستعد خطا.
مثال: تنظیمات پیکربندی
بیایید بگوییم که ما به یک پیکربندی با مقدار زمان بندی نیاز داریم. یک اشتباه رایج استفاده از یک اشاره گر است:
type Config struct {
Timeout *int
}
اکنون ، هر بار که می خواهیم از آن استفاده کنیم ، باید بررسی کنیم که آیا این است nil
:
if config.Timeout != nil {
fmt.Println("Timeout is set to:", *config.Timeout)
} else {
fmt.Println("No timeout set")
}
این باعث می شود کد پیچیده تر از حد لازم باشد. در عوض ، ما می توانیم از a استفاده کنیم عدد صحیح ساده با پرچم بولی:
type Config struct {
Timeout int
IsSet bool
}
اکنون ، ما بررسی می کنیم که آیا IsSet
درست است:
if config.IsSet {
fmt.Println("Timeout is set to:", config.Timeout)
} else {
fmt.Println("No timeout set")
}
چرا این بهتر است؟
- نیازی به چک های صفر نیست.
- هیچ تخصیص حافظه اضافی برای نشانگرها وجود ندارد.
- کد ساده تر ، قابل خواندن تر.
پیشخدمت
-
از نشانگرها استفاده کنید هنگامی که شما نیاز به تمایز بین “UNSET” و “ZERO VALE” (به خصوص در JSON و API) دارید.
-
از انواع ارزش استفاده کنید هنگامی که یک مقدار صفر کافی است و نیازی به ردیابی داده های گمشده به طور جداگانه نیست.
-
از نشانگرهای غیر ضروری خودداری کنید برای تمیز نگه داشتن کد GO خود ، حفظ آن آسان است.
با پیروی از این قوانین ساده ، شما می نویسید کد بهتر با سردردهای کمتری!