رابط ها (Interfaces)
رابطها انواعی هستند که فقط شامل تعاریفی برای متدها میباشند. رابطها را میتوان به عنوان پلاگین های ساختار در نظر گرفت. ساختاری که یک رابط خاص را پیاده سازی میکند لازم است که کدهایی برای اجرا توسط اعضا و متدهای آن فراهم کند چون اعضا و متدهای رابط هیچ کد اجرایی در بدنه خود ندارند. اجازه دهید که نحوه تعریف و استفاده از یک رابط در ساختار را توضیح دهیم :
1: package main 2: 3: import "fmt" 4: 5: type CA struct { 6: FullName string 7: Age int 8: } 9: 10: type CB struct { 11: FirstName string 12: LastName string 13: PersonsAge int 14: } 15: 16: func PrintInfo(item CA) { 17: fmt.Printf("Name: %s, Age %d \n", item.FullName, item.Age); 18: } 19: 20: func main() { 21: a := CA{FullName: "John Doe", Age: 35} 22: 23: PrintInfo(a) 24: }
در کد بالا دو ساختار CA و CB تعریف شدهاند، در ساختار CA دو متغیر به نام FullName و Age و در ساختار CB سه متغیر به نامهای FirstName و LastName ,PersonsAge تعریف کردهایم. در برنامه بالا، یک متد به نام ()PrintInfo داریم که یک پارامتر از نوع ساختار CA دارد. به شکل ساده در این متد مقدار متغیرهایشی ای که به این متد ارسال شده است، چاپ میشود. در متد ()main یک شیء از ساختار CA ساختهایم و متغیرهای آن را مقدار دهی کردهایم (خط 21). سپس این شیء را به متد PrintInfo ارسال میکنیم (خط 23). ساختارهای CA و CB از نظر مفهومی شبیه یکدیگر هستند. مثلاً ساختار CA متغیر FullName را برای نمایش نام و نام خانوادگی دارد ولی ساختار CB برای نمایش نام و نام خانوادگی دو متغیر جدا از هم به نامهای FirstName و LastName را دارد. و همچنین یک متغیر برای نگهداری مقدار سن داریم که در ساختار CA نام آن Age و در ساختار CB نام آن PersonAge میباشد. مشکل اینجاست که اگر ما یک نمونه از ساختار CA را به متد (PrintInfo) ارسال کنیم، از آنجایی که در داخل بدنه این متد فقط مقدار دو متغیر چاپ میشود، اگر بخواهیم یک نمونه از ساختار CB را به آن ارسال کنیم که دارای سه متغیر است با خطا مواجه میشویم (زیرا متد ()PrintInfo با ساختار ساختار CA سازگار است و متغیرهای CB را نمیشناسد). برای رفع این مشکل باید ساختار دو ساختار CA و CB را شبیه هم کنیم و این کار را با استفاده از Interface انجام میدهیم:
1: package main 2: 3: import "fmt" 4: 5: type IInfo interface { 6: GetName() string 7: GetAge() int 8: } 9: 10: type CA struct { 11: FullName string 12: Age int 13: } 14: 15: type CB struct { 16: FirstName string 17: LastName string 18: PersonsAge int 19: } 20: 21: func (a CA) GetName() string { 22: return a.FullName 23: } 24: 25: func (a CA) GetAge() int { 26: return a.Age 27: } 28: 29: func (b CB) GetName() string { 30: return b.FirstName + " " + b.LastName 31: } 32: 33: func (b CB) GetAge() int { 34: return b.PersonsAge 35: } 36: 37: func PrintInfo(item IInfo) { 38: fmt.Printf("Name: %s, Age %d \n", item.GetName(), item.GetAge()); 39: } 40: 41: func main() { 42: a := CA {FullName: "John Doe", Age: 35} 43: b := CB { FirstName: "Jane", LastName: "Rock", PersonsAge: 33} 44: 45: PrintInfo(a) 46: PrintInfo(b) 47: }
Name: John Doe, Age 35 Name: Jane Rock, Age 33
کد بالا را میتوان به اینصورت توضیح داد که، در خط 8-5 یک رابط به نام IInfo تعریف کردهایم. برای پیاده سازی یک رابط در Go لازم نیست کار خاصی انجام دهیم. همین که متدهای آن را پیاده سازی و کدهای بدنه آنها را تکمیل کنیم، کفایت میکند. دو ساختار وظیفه دارند متدهای این رابط را پیاده سازی کنند، پس در خطوط 27-21 و 39-33 کدهای بدنه دو متد این رابط را آن طور که میخواهیم، مینویسیم. در خط 37 متد ()PrintInfo را طوری دستکاری میکنیم که یک پارامتر از نوع رابط دریافت کند. حال زمانی که دو نمونه از دو ساختار CA و CB در دو خط 42 و 43 ایجاد میکنیم و آنها را در دو خط 45 و 46 به متد ()PrintInfo ارسال میکنیم، چونکه این دو ساختار متدهای رابط IInfo را پیاده سازی کردهاند، به طور صریح به رابط تبدیل میشود. یعنی ساختاری که یک رابط را پیاده سازی کند، به طور صریح میتواند به رابط تبدیل شود. حال بسته به اینکه شیء کدام ساختار به متد ()PrintInfo ارسال شده است، متد مربوط به آن ساختار فراخوانی شده و مقادیر متغیرها چاپ میشود.