في أبسط صورها، نوع الواجهة هو مجموعة من توقيعات الطرق.
إليك مثالًا على تعريف واجهة يتضمن طريقتين هما Add و Value:
type Counter interface {
Add(increment int)
Value() int
}
يمكن حذف أسماء المعاملات مثل increment من تعريف الواجهة، لكنها غالبًا ما تزيد من قابلية القراءة.
أسماء الواجهات في Go لا تحتوي على الكلمة Interface أو الحرف I.
بل غالبًا ما تنتهي بـ er، مثل Reader و Stringer.
أي نوع يعرّف طرق الواجهة ينفّذ الواجهة تلقائيًا وضمنيًا.
لا توجد كلمة مفتاحية implements في Go.
النوع التالي ينفّذ واجهة 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 التي أعددتها في المهمة 1.
يمكنك تحية شخص ما بالإيطالية بعبارة "Ciao {name}!".
قبل أن تنهي عملك لليوم، يُفترض أيضًا أن تكمل وظيفة تحية الناس بالبرتغالية.
لذلك، أنشئ بنية Portuguese ونفّذ الطريقتين اللازمتين لكي تحقق البنية واجهة Greeter هنا أيضًا.
يمكنك تحية شخص ما بالبرتغالية بعبارة "Olá {name}!".
سجّل في Exercism لتتعلّم وتتقن Go عبر 34 مفهومًا166 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.