برنامه نویسی

Go Beginners Series: Data Structures, Structs, and Pointers

هنگام نوشتن برنامه های کاربردی متوسط ​​در Go، باید مواردی مانند سازماندهی کد، مدیریت حافظه، دسترسی به داده ها و انعطاف پذیری کد را در نظر داشته باشید. اغراق نکنیم.

به عنوان مثال، شما فقط می توانید کارهای زیادی را با انواع داده های معمولی انجام دهید. در واقع، برای اکثر برنامه‌ها، برای سازماندهی بهتر کد، خوانایی و ترکیب‌پذیری، باید چندین مقدار را در یک واحد تعریف و ذخیره کنید. همچنین، استفاده از نشانگرها در برنامه‌های Go شما مزایای زیادی دارد، مانند مدیریت کارآمد حافظه، دستکاری مستقیم داده‌ها، ایجاد ساختارهای داده پویا و بسیاری موارد دیگر.

در این مقاله، همه چیزهایی را که برای شروع استفاده از اشاره گرها و ساختارها برای ساخت برنامه های Go کارآمدتر و قابل اعتمادتر نیاز دارید، یاد خواهید گرفت.

ساختارهای داده

در برنامه نویسی، یک ساختار داده داده ها را سازماندهی و در حافظه کامپیوتر ذخیره می کند. یک ساختار داده را می توان محفظه ای در نظر گرفت که مجموعه ای از اقلام داده مرتبط را در خود نگه می دارد و روابط آنها را تعریف می کند. ساختارهای داده در برنامه نویسی ضروری هستند زیرا به شما امکان می دهند داده ها را ذخیره کرده و به آنها دسترسی داشته باشید و عملیات روی آن را به طور موثر انجام دهید.

انواع مختلفی از ساختارهای داده وجود دارد که هر کدام نقاط قوت و ضعف خود را دارند و هر کدام برای وظایف یا موارد استفاده خاص مناسب هستند.

ساختارهای داده رایج

آرایه ها: یک ساختار داده ساده که مجموعه ای از موارد از یک نوع را در مکان های حافظه پیوسته ذخیره می کند. آرایه‌ها را می‌توان با نمایه‌سازی در دسترس قرار داد و به پیاده‌سازی الگوریتم‌های دسترسی متوالی به داده‌ها کمک کرد.

لیست های مرتبط: یک ساختار داده پویا که متشکل از دنباله ای از گره ها است که هر کدام شامل یک عنصر داده و یک اشاره گر به گره بعدی در سری است. لیست های پیوندی به پیاده سازی الگوریتم هایی کمک می کند که به عملیات درج و حذف مکرر نیاز دارند.

پشته ها: ساختار داده ای که عناصر را به ترتیب Last-In-First-Out (LIFO) ذخیره می کند. پشته‌ها برای پیاده‌سازی الگوریتم‌هایی که نیاز به عملیات بازگشت یا لغو دارند، مفید هستند.

دم: ساختار داده ای که عناصر را به ترتیب First-In-First-Out (FIFO) ذخیره می کند. خطوط به پیاده سازی الگوریتم هایی که نیاز به زمان بندی یا ارسال پیام دارند کمک می کند.

درختان: یک ساختار داده سلسله مراتبی که شامل گره هایی است که توسط لبه ها به هم متصل شده اند. درختان به نمایش روابط سلسله مراتبی بین عناصر داده، مانند ساختار یک سیستم فایل یا سازمان یک شرکت کمک می کنند.

نمودارها: ساختار داده ای که اشیاء (رئوس یا گره ها) را نشان می دهد که توسط لبه ها به هم متصل شده اند. نمودارها به مدل سازی روابط بین عناصر داده، مانند شبکه های اجتماعی و حمل و نقل کمک می کنند.

انتخاب ساختار داده به مشکل حل شده و الزامات عملکرد برنامه بستگی دارد. استفاده کارآمد از ساختارهای داده برای نوشتن برنامه های با کارایی بالا حیاتی است و درک مبادلات بین ساختارهای داده مختلف یک مهارت ضروری برای هر برنامه نویسی است.

بیایید نگاهی به ساختارها و نحوه استفاده از آنها در go در بخش بعدی بیاندازیم.

سازه ها

Go شما را قادر می سازد تا داده های مرتبط را در یک واحد با استفاده از ساختارها تعریف کنید. ساختار یک نوع داده است که گروهی از فیلدها را در خود جای می دهد. به عنوان مثال، اگر می خواهید اطلاعات کاربر را در یک مکان مشخص کنید، می توانید این کار را به صورت زیر انجام دهید:

type User struct {
 name      string
 email     string
 accessLvl string
 age       int
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کد بالا a را تعریف می کند User ساخت با name، email، accessLvl، و age زمینه های. پس از تعریف ساختار، اکنون می توانید از مقدار زیر استفاده کنید:

 user := User{"John Kenneth", "jken@ml.com", "admin", 40}
 fmt.Printf("Your username is %s, your email is %s, and your access level is %s and your age is %d", user.name, user.email, user.accessLvl, user.age)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کد بالا a را تعریف می کند user متغیر که نوعی از User با یک مقدار برای تمام فیلدها، و مقادیر را با پیامی مانند این چاپ می کند:

Your username is John Kenneth, your email is jken@ml.com, and your access level is admin, and your age is 40
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هنگام تعریف یک متغیر ساختار، لازم نیست برای همه فیلدها مقداری تعریف کنید. می توانید با آن کار کنید User ساختار به این صورت:

 user := User{
  name:  "John Kenneth",
  email: "jkem@ml.com",
  age:   40,
 }
 user.accessLvl = "admin"
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کد بالا قسمت هایی از را تعریف می کند user متغیرها بر اساس اعلامیه و سایر قسمت ها پس از آن. کد بالا همان نتیجه قبلی را نشان می دهد.

فیلدهای تعبیه شده

یک ساختار می تواند یک فیلد در داخل ساختار دیگر برای کاهش تکرار کد باشد. برای مثال می توانید از User ساختار داخل Employee struct برای جلوگیری از تکرار فیلدهای مشابه در داخل آن مانند این است:

type Employee struct {
 User
 salary int
 role   string
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون می توانید یک متغیر را بر اساس آن تعریف کنید Employee ساختار مانند این است:


 employee := Employee{
  User: User{
   name:  "John Kenneth",
   email: "jken@ml.com",
   age:   40,
  },
  salary: 50000,
  role:   "Developer",
 }
 fmt.Printf("Your employee name is %s, your email is %s, and your access level is %s, and your age is %d. While your role is %s and your salary is %d", employee.name, employee.email, employee.accessLvl, employee.age, employee.role, employee.salary)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کد بالا یک پیام بر اساس employee متغیر مانند این:

Your employee name is John Kenneth, your email is jken@ml.com, and your access level is admin, and your age is 40. While your role is Developer and your salary is 50000
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

توجه: نام فیلدها باید منحصر به فرد باشد. با این حال، اگر لازم است یک ساختار مشابه را دو بار جاسازی کنید، باید پیشوند آن را با نامی مانند زیر وارد کنید: Other User، و با نام قابل دسترسی خواهد بود Other.

سازه های ناشناس

ساختارهای ناشناس در Go زمانی استفاده می شوند که شما نیاز به تعریف یک نمونه از ساختار دارید. شما می توانید ساختارهای ناشناس را به این صورت تعریف کنید:

 car := struct {
  brand string
  model string
  year  int
  price int
 }{
  brand: "Toyota",
  model: "Vios",
  year:  2020,
  price: 1000000,
 }

 fmt.Printf("The brand of the car is %s, the model is %s, the year is %d, and the price is %d", car.brand, car.model, car.year, car.price)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کد بالا یک ساختار ناشناس را تعریف می کند car و بر اساس مقادیر آن پیامی را چاپ می کند. کد بالا باز خواهد گشت:

The brand of the car is Toyota, the model is Vios, the year is 2020, and the price is 1000000
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

روش های گیرنده

Go به شما اجازه می دهد تا توابعی را تعریف کنید که فقط روی نمونه هایی از ساختارها کار می کنند. به عنوان مثال، اگر می خواهید تابعی ایجاد کنید که یک کارمند را توصیف کند، می توانید از یک تابع گیرنده مانند زیر استفاده کنید:

func (u *Employee) describe() string {
 desc := fmt.Sprintf("Name: %s, Email: %s, Age: %d, Salary: %d, Role: %s", u.name, u.email, u.age, u.salary, u.role)
 return desc
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کد بالا یک تابع را تعریف می کند، describe، که فقط روی نمونه هایی از Employee یک پیام را با اطلاعات کارمند ساخته و چاپ می کند. اکنون می توانید از تابع روی متغیری مانند زیر استفاده کنید:

fmt.Println(employee.describe())
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کد بالا باز خواهد گشت:

Name: John Kenneth, Email: jken@ml.com, Age: 40, Salary: 5000, Role: CEO
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

توجه: بریس هایی که قبل از نام تابع قرار می گیرند حاوی عبارت هستند گیرنده، یک اشاره گر از نوعی که تابع روی آن عمل می کند. بیشتر در مورد اشاره گرها در ادامه مقاله.

مزایای Structs in Go

در Go، ساختارها یک نوع داده ترکیبی قدرتمند هستند که مزایای متعددی را نسبت به انواع داده‌های دیگر مانند آرایه‌ها یا نقشه‌ها ارائه می‌کنند. برخی از مزایای کلیدی استفاده از ساختارها در Go شامل موارد زیر است:

کپسوله سازی: ساختارها به شما این امکان را می دهند که داده های مرتبط را با هم در یک شی واحد کپسوله کنید، که می تواند به بهبود سازماندهی کد و قابلیت نگهداری کمک کند. این باعث می‌شود که استدلال در مورد داده‌های مورد استفاده در برنامه شما آسان‌تر شود و خطر خطاهای ناشی از تغییر تصادفی داده‌های اشتباه کاهش می‌یابد.

روش های ساختاری: ساختارهای Go می‌توانند متدهای مرتبطی داشته باشند که به شما امکان می‌دهند رفتاری خاص برای یک نوع ساختار خاص تعریف کنید. این می تواند به ساده سازی کد شما و کاهش کد دیگ بخاری که باید بنویسید کمک کند.

نوع ایمنی: Go یک زبان استاتیک تایپ شده است، به این معنی که نوع متغیر در زمان کامپایل شناخته می شود. استفاده از ساختارها می تواند به اطمینان از سازگاری انواع داده های شما کمک کند و می تواند به کشف خطاها در زمان کامپایل کمک کند.

بهره وری: Structs in Go به گونه ای طراحی شده اند که سبک و کارآمد باشند، به این معنی که می توانند ساختارهای داده پیچیده را بدون اعمال جریمه عملکرد قابل توجه نشان دهند.

انعطاف پذیری: Structs در Go را می توان در ساختارهای دیگر تو در تو قرار داد و به شما این امکان را می دهد که ساختارهای داده پیچیده ای ایجاد کنید که به راحتی قابل دستکاری و پردازش باشند.

استفاده از ساختارهایی در Go که به بهبود سازماندهی کد، کاهش خطاها و بهبود عملکرد کمک می کند و همچنین برنامه ها را کارآمدتر، قابل نگهداری و انعطاف پذیرتر می کند.

بیایید اشاره گرها و نحوه استفاده از آنها را در بخش بعدی بررسی کنیم.

اشاره گرها

Go به شما این امکان را می دهد که با استفاده از نشانگرها، تغییر ناپذیری را برای کارایی در کد خود قربانی کنید. اشاره گر در Go آدرس حافظه یک متغیر معین است. به عنوان مثال، هنگامی که یک متغیر در Go ایجاد می کنید، یک آدرس حافظه منحصر به فرد به نظر می رسد 0xc00000c0c0 به طور خودکار به متغیر اختصاص داده می شود و می توان از آن برای انجام کارهای مختلف در کد خود استفاده کرد.

یک مورد عالی برای استفاده از اشاره گرها در Go، تغییر مقدار یک متغیر در داخل و خارج از محدوده تابع است تا از ایجاد کپی های بیش از حد از متغیر در سراسر برنامه جلوگیری شود. به عنوان مثال، وقتی تابعی ایجاد می‌کنید که یک متغیر از قبل تعریف شده را می‌پذیرد و تغییر می‌دهد، متغیر تغییر نخواهد کرد. در عوض، Go یک مرجع از آن متغیر را فقط برای فراخوانی تابع ایجاد می کند. بیایید نمونه ای از آن را با یک تابع ببینیم:

var age = 40

func updateAge(age int) {
 age = 100
 fmt.Println(age)
}
func main() {
 fmt.Println("Here is the value of age before calling updateAge: ", age)
 updateAge(age)
 fmt.Println("Here is the value of age after calling updateAge: ", age)
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کد بالا یک متغیر تعریف می کند، age، یک تابع، updateAge که یک عدد را می گیرد، مقدار آن را به آن اختصاص می دهد 100، و آن را چاپ می کند. در نهایت، پیامی با مقدار از چاپ می کند age قبل و بعد از تماس با updateAge تابع با متغیر سن کد بالا باید نتیجه زیر را برگرداند:

Here is the value of age before calling updateAge:  40
100
Here is the value of age after calling updateAge:  40
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

را updateAge تابع همانطور که انتظار می رفت کار می کرد، اما نمی توانست مقدار آن را تغییر دهد age به دلیل اصل ارزش عبوری Go. بنابراین چگونه می توانید مقدار واقعی را تغییر دهید age متغیر؟ ابتدا، بیایید ببینیم که چگونه آدرس حافظه یک متغیر را چاپ کنیم.

آدرس های حافظه

همانطور که قبلا ذکر شد، هر متغیری در Go دارای یک آدرس حافظه است که هنگام ایجاد به آن اختصاص داده شده است. با استفاده از دستور زیر می توانید به آدرس دسترسی پیدا کنید:

fmt.Println("age pointer is: ", &age) // age pointer is:  0x6bd320
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کد بالا پیامی را با age آدرس حافظه متغیر مانند این است:

age pointer is:  0x6bd320
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برای خود آدرس حافظه کاربرد کمی وجود دارد، اما می توانید هر کاری که می خواهید با آن انجام دهید.

عدم ارجاع

می توانید مشکلی را که قبلا دیدید با updateAge عملکرد با عدم ارجاع این روشی برای انتقال مقدار یک متغیر به یک تابع است تا بتواند متغیر را مستقیماً تغییر دهد. قسمت های زیر از بلوک کد قبلی را به این صورت ویرایش کنید:

func updateAge(age *int) {
 *age = 100
 fmt.Println(*age)
}

// function call
 updateAge(&age)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کد بالا بازنویسی می کند updateAge تابعی برای پذیرش یک اشاره گر به عنوان پارامتر به جای متغیر. سپس از ارجاع مجدد با پیشوند نام پارامتر با استفاده می کند * و تماس می گیرد updateAge عملکرد با اشاره گر با پیشوند age متغیر با &. کد بالا اکنون باید برگردد:

Here is the age before calling updateAge:  40
100
Here is the age after calling updateAge:  100
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برای درک بهتر آدرس حافظه و نحو ارجاع مجدد، کد زیر را در نظر بگیرید:

 fmt.Println("age pointer is: ", &age)
 fmt.Println("age value is: ", age)
 fmt.Println("You can also access the value using with: ", (*&age))
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کد بالا موارد زیر را برمی گرداند:

age pointer is:  0x8ae320
age value is:  40
You can also access the value using with:  40
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

مزایای استفاده از اشاره گر در Go

استفاده از نشانگرها در کد Go به شما امکان می دهد داده ها را به طور موثرتری دستکاری و اصلاح کنید و مزایای زیادی دارد. بیایید در این بخش به بررسی برخی از آنها بپردازیم.

تغییر متغیرها

هنگامی که می خواهید مقدار متغیری را در داخل یک تابع تغییر دهید – اگر یک متغیر را به یک تابع بر اساس مقدار ارسال کنید، هر گونه تغییری که در متغیر داخل تابع ایجاد شود، روی متغیر اصلی تأثیر نخواهد گذاشت. در عوض با ارسال یک اشاره گر به متغیر، تابع می تواند مقدار اصلی را مستقیماً تغییر دهد.

از کپی غیر ضروری خودداری کنید

هنگامی که می خواهید از کپی ساختارهای داده بزرگ خودداری کنید – در Go، ارسال ساختارهای داده بزرگ بر اساس ارزش می تواند ناکارآمد باشد، زیرا نیاز به ایجاد یک کپی جدید از کل ساختار دارد. با ارسال یک اشاره گر به ساختار به جای آن، می توانید از این کپی غیر ضروری جلوگیری کنید و عملکرد را بهبود بخشید.

به اشتراک گذاری داده ها بین توابع

هنگامی که می خواهید داده ها را بین توابع به اشتراک بگذارید – در برخی موارد، ممکن است بخواهید داده ها را بین چندین تابع یا بسته به اشتراک بگذارید. ارسال یک اشاره گر به داده ها به چندین تابع اجازه می دهد تا به همان داده ها دسترسی پیدا کرده و آنها را تغییر دهند.

پیاده سازی ساختارهای داده

وقتی می‌خواهید ساختارهای داده مانند فهرست‌های پیوندی یا درختان را پیاده‌سازی کنید – ساختارهای داده مانند فهرست‌های پیوندی و درخت‌ها نیاز به ذخیره‌سازی اشاره‌گرها به گره‌های دیگر در ساختار دارند. با استفاده از اشاره گرها، می توانید به راحتی این ساختارهای داده پیچیده را ایجاد و دستکاری کنید.

مهم است که از اشاره گرها با دقت استفاده کنید و اطمینان حاصل کنید که حافظه را به درستی مدیریت می کنید تا از اشکالات و نشت حافظه جلوگیری کنید. با این حال، اشاره گرها می توانند ابزاری قدرتمند برای برنامه نویسی کارآمد و انعطاف پذیر در Go در صورت استفاده صحیح باشند.

نتیجه

ساختارها و اشاره گرها ویژگی های مهم Go هستند و درک آن می تواند بسیار پیچیده باشد. با این حال، امیدوارم این مقاله بتواند آنچه را که برای شروع کار با ساختارها و اشاره گرها در Go باید بدانید را به شما آموزش دهد. شما در مورد اشاره گرها، عدم ارجاع، ساختارها، ساختارهای جاسازی شده، ساختارهای ناشناس و مزایای استفاده از آنها در برنامه های Go خود یاد گرفتید.

لطفا در صورت داشتن هر گونه سوال، پیشنهاد یا اصلاح نظر خود را بنویسید. من مطمئن خواهم شد که به همه آنها پاسخ خواهم داد.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا