[৩.১] স্ট্রাক্টচার বা স্ট্রাক্টস (Structure or Structs)

বুটক্যাম্পের এই পর্যায়ে আমরা পরিচিত হবো Go Struct এর সাথে। এর মাধ্যমে যেভাবে Go, Object Oriented কনসেপ্টের সাথে নিজেকে সংশ্লিষ্ট করেছে, সেভাবেই Struct এর মাধ্যমে অন্যান্য Object Oriented Programming Language এর কনভেনশনের বাইরে একটা আলাদা স্বরূপ তৈরি করে নিয়েছে। Go ব্যবহার করে যেকোনো পরিসরে কাজ করার জন্য Struct সম্পর্কে পরিষ্কার ধারণা থাকাটা একটা আবশ্যক ব্যাপার। 

[৩.১.১] Struct  কী ?

Struct হলো ইউজারের নিজ প্রয়োজনে বানিয়ে নেয়া একটি কাস্টম ডাটা টাইপ যেখানে ভিন্ন ভিন্ন ডাটা টাইপকে একটি এনটিটির ভেতরে একত্র করা যায়। ব্যাপারটা অনেকটা এমন যে, আমাদের বাস্তব জগতের যেকোনো বস্তু, যার নিজের কিছু প্রোপার্টি আছে, তা এই Struct এর মাধ্যমে প্রকাশ করা যাবে। অতএব আমরা বলতে পারি যে, Struct হলো কিছুটা  Object Oriented programming এর Class কনসেপ্টের মতোই যা Class এর তুলনায় অনেক দ্রুত ও কার্যকর। পরবর্তীতে যখন আমরা মেথড নিয়ে আলোচনা করব তখন এই ব্যাপারে আরো বিস্তারিত জানতে পারব। আপাতত আমরা Struct এর গঠন এবং ব্যবহারে ফোকাস করি

[৩.১.২] Struct এর গঠন

একটি Struct ডিফাইন বা গঠন করা হয় নিম্নলিখিত সিনট্যাক্সের মাধ্যমে

				
					  type StructName struct {
       Field1 datatype
       Field2 datatype
       //................
   }

				
			

উদাহরণস্বরূপ একটি Player Struct ডিফাইন করা যেতে পারে এভাবে  :

				
					 type Player struct {
       name  string
       age   int
       city  string
       state string
   }

				
			

এখানে type এবং struct হল দুইটি  keyword। Player হল Struct এর নাম। name, age, city, state হল Struct এর ফিল্ড বা প্রোপার্টি এবং int, string হল ফিল্ডের ডাটা টাইপ। 

আমরা চাইলে একই ডাটা টাইপের ফিল্ডগুলো একসাথে সংক্ষিপ্তভাবে ডিফাইন করতে পারি –

				
					   type Player struct {
       name, city, state string
       age   int
   }

				
			

এখানে উল্লেখিত প্রত্যেকটি ফিল্ড কিন্তু Unexported, অর্থাৎ এই ফিল্ড গুলোকে অন্য কোন প্যাকেজ থেকে অ্যাক্সেস করা যাবে না। Go তে struct এর ফিল্ড গুলো প্যাকেজের বাইরে ব্যবহার করা যাবে কি যাবে না সেটা নির্ভর করছে এর নামের উপর। কনভেনশন অনুযায়ী, নামের প্রথম অক্ষর যদি বড় হাতের হয়ে থাকে তাহলে তা Exported ধরা হয় এবং অন্য প্যাকেজ থেকে অ্যাক্সেস করা যায় – 

				
					   type Player struct {
       Name  string // Exported
       Age   int
       city  string // Unexported
       state string
   }

				
			

[৩.১.৩] Struct এর ইনস্ট্যান্স তৈরি

আমরা কয়েকভাবেই  Struct -এর ইনস্ট্যান্স  তৈরি করতে পারি – 

  • প্রথমে var কিওয়ার্ড ব্যবহার করে Struct টাইপের ভ্যারিয়েবল তৈরি করি। একবার ভ্যারিয়েবল ডিক্লেয়ার করার পর এর প্রোপার্টিগুলো আমরা এক এক করেও সেট করতে পারি –
				
					 package main

   import "fmt"

   type Player struct {
       Name string
       Age  int
       City string
   }

   func main() {
       var player1 Player
	  //set the value for player1 struct/object property
       player1.Name = "Any name"
       player1.Age = 23
       player1.City = "Any city"
       fmt.Println(player1)

       // Output : {Any name 23 Any city}
   }

				
			
  • Struct লিটেরাল ব্যবহার করে সরাসরি ভ্যালুগুলো সেট করে দিতে পারি – 

 

				
					package main

   import "fmt"

   type Player struct {
       Name string
       Age  int
       City string
   }

   func main() {
       player2 := Player{"Another name", 34, "Another city"}

       fmt.Println(player2)

       //Output : {Another name 34 Another city}
   }

				
			
  • Struct এর প্রত্যেক ভ্যালু চাইলে আলাদা আলাদা ভাবেও অ্যাক্সেস করা যায়। সেক্ষেত্রে উপরে যেভাবে এক এক করে ভ্যালু সেট করেছিলাম, ওভাবেই আলাদা করে নানান জায়গা থেকে অ্যাক্সেস করা যাবে।

[৩.১.৪] নেস্টেড Struct 

যেহেতু Struct ও একধরণের ডাটা টাইপ, সুতরাং দরকারে একটা Struct আরেকটা Struct এর ফিল্ড হিসেবে ব্যবহার করা যাবে –

				
					 type Address struct {
       street string
       city   string
       state  string
       zip    string
   }


   type Person struct {
       name    string
       age     int
       address Address
   }

				
			

উপরের উদাহরণে আমরা Address এর একটা ইন্সট্যান্স Person Struct এর ভেতরে রেখেছি। চাইলে একাধিক ইন্সট্যান্স ও রাখতে পারতাম অ্যারে হিসেবে – 

				
					type Person struct {
       name    string
       age     int
       addresses []Address
   }

				
			

[৩.১.৫] Struct এর পয়েন্টার 

আমরা চাইলে Struct এর ইন্সট্যান্স তৈরি করার সময় তা পয়েন্টার দ্বারা করতে পারি –

				
					package main

   import "fmt"

   type Address struct {
       street string
       city   string
       state  string
       zip    string
   }
   type Person struct {
       name    string
       age     int
       address Address
   }

   func main() {
       person := &Person{
           name: "Bob",
           age:  35,
           address: Address{
               street: "789 Broadway",
               city:   "New York",
               state:  "NY",
               zip:    "10003",
           },
       }

       fmt.Println(person)
       // Output : &{Bob 35 {789 Broadway New York NY 10003}}
   }

				
			

উপরের উদাহরণে Person Struct এর একটি ইন্সট্যান্স পয়েন্টার এর সাথে এবং ভ্যালুগুলো Struct লিটেরাল দ্বারা ডিক্লেয়ার করা হয়েছে। আমরা জানি, পয়েন্টার দিয়ে এখানে অবজেক্টের লোকেশন নির্দেশ করা হয়েছে। এভাবে পয়েন্টার দ্বারা Struct এর ব্যবহার অনেক ক্ষেত্রেই আবশ্যক হয়ে দাঁড়ায়। কোনো কারণে যদি Struct এর আকার অনেক বড় হয়ে থাকে সেক্ষেত্রে ভ্যালু হিসেবে পাস করলে স্পেস কমপ্লেক্সিটি অনেক বেড়ে যায়, কপি হিসেবে সেন্ড হওয়ার কারণে। কিন্তু পয়েন্টার হিসেবে পাস করলে বাড়তি স্পেসের প্রয়োজন হয় না।