در سادهترین شکل خود، «نوع رابط» مجموعهای از امضاهای متد است.
در ادامه نمونهای از تعریف یک رابط را میبینید که دو متد Add و Value دارد:
type Counter interface {
Add(increment int)
Value() int
}
نام پارامترهایی مانند increment را میتوان از تعریف رابط حذف کرد، اما معمولاً خوانایی را بیشتر میکنند.
نام رابطها در Go شامل واژهی Interface یا I نیست.
بهجای آن، معمولاً به er ختم میشوند، مانند Reader و Stringer.
هر نوعی که متدهای رابط را تعریف کند، بهطور خودکار و ضمنی رابط را «پیادهسازی» میکند.
در Go کلیدواژهی implements وجود ندارد.
نوع زیر رابط Counter را که در بالا دیدیم، پیادهسازی میکند.
type Stats struct {
value int
// ...
}
func (s Stats) Add(v int) {
s.value += v
}
func (s Stats) Value() int {
return s.value
}
func (s Stats) SomeOtherMethod() {
// The type can have additional methods not mentioned in the interface.
}
برای پیادهسازی رابط، فرقی نمیکند که متد گیرندهی مقداری داشته باشد یا گیرندهی اشارهگر. (اگر دربارهی آنها مطمئن نیستید، مفاهیم متدها را دوباره ببینید.)
یک مقدار از نوع رابط میتواند هر مقداری را که آن متدها را پیادهسازی میکند، نگه دارد. [^1]
یعنی اکنون میتوان از Stats در همهی جاهایی استفاده کرد که انتظار رابط Counter را دارند.
func SetUpAnalytics(counter Counter) {
// ...
}
stats := Stats{}
SetUpAnalytics(stats)
// works because Stats implements Counter
چون رابطها بهصورت ضمنی پیادهسازی میشوند، یک نوع بهراحتی میتواند چندین رابط را پیادهسازی کند. فقط کافی است همهی متدهای لازم را تعریف کرده باشد.
یک نوع رابط بسیار خاص در Go وجود دارد: «رابط خالی» که هیچ متدی ندارد.
رابط خالی به این شکل نوشته میشود: interface{}.
any معادلی برای interface{} است و کاربردش رایجتر است.
چون رابط خالی هیچ متدی ندارد، هر نوعی آن را بهصورت ضمنی پیادهسازی میکند. این موضوع برای تعریف تابعی مفید است که بتواند بهشکل عمومی هر مقداری را بپذیرد. در این حالت، پارامتر تابع از نوع رابط خالی استفاده میکند.
فرودگاه جدید برلین برای آزمایشگاه رباتیکش توسعهدهنده استخدام کرده است و شما کارتان را از همانجا شروع میکنید. آنها رباتهایی دستوپاگیر با ظاهری تا حدی انساننما دارند که میخواهند با کمکشان خدمات مشتریان را بهبود بدهند.
اولین وظیفهی شما در این شغل این است که برنامهای بنویسید تا ربات بتواند پس از اینکه مسافران گذرنامهشان را در باجهی پذیرش خودکار اسکن کردند، به زبان مادریشان به آنها خوشآمد بگوید.
ربات به تواناییهایش افتخار میکند، پس همیشه اول میگوید به چه زبانی میتواند صحبت کند و بعد به فرد خوشآمد میگوید. برای مثال، اگر کسی گذرنامهی آلمانی اسکن کند، ربات میگوید:
I can speak German: Hallo Dietrich!
شما خودتان کد زبانهای مختلف را نمینویسید، پس باید کد ربات را طوری ساختاردهی کنید که توسعهدهندگان دیگر بتوانند بهراحتی بعداً زبانهای بیشتری اضافه کنند.
بهعنوان قدم اول، یک «رابط» Greeter با دو «متد» تعریف کنید.
LanguageName که اسم زبانی را برمیگرداند (یک string) که قرار است ربات با آن به بازدیدکننده خوشآمد بگوید.Greet که اسم بازدیدکننده را میگیرد (یک string) و یک string شامل پیام خوشآمدگویی به یک زبان مشخص را برمیگرداند.بعد، تابعی به اسم SayHello پیادهسازی کنید که اسم بازدیدکننده و هر نوعی که رابط Greeter را پیادهسازی میکند بهعنوان ورودی میگیرد و رشتهی خوشآمدگویی موردنظر را برمیگرداند.
برای مثال، یک پیادهسازی آلمانی از Greeter را در نظر بگیرید که LanguageName مقدار "German" را برمیگرداند و Greet مقدار "Hallo {name}!" را:
SayHello("Dietrich", germanGreeter)
// => "I can speak German: Hallo Dietrich!"
حالا وظیفهی شما این است که ربات را برای کسانی که گذرنامهی ایتالیایی اسکن میکنند هم به کار بیندازید.
برای این کار، یک «ساختار» Italian بسازید و آن دو متدی را پیادهسازی کنید که ساختار برای برآورده کردن رابط Greeter به آنها نیاز دارد؛ همان رابطی که در وظیفهی ۱ ساختید.
میتوانید به کسی به ایتالیایی با "Ciao {name}!" خوشآمد بگویید.
پیش از آنکه کار را تمامشده بدانید، قرار است قابلیت خوشآمدگویی به پرتغالی را هم کامل کنید.
برای این کار، یک ساختار Portuguese بسازید و آن دو متدی را هم که ساختار برای برآورده کردن رابط Greeter به آنها نیاز دارد، پیادهسازی کنید.
میتوانید به کسی به پرتغالی با "Olá {name}!" خوشآمد بگویید.