الطريقة هي دالة لها وسيط خاص هو المستقبِل.
يظهر المستقبِل في قائمة وسائط خاصة به بين الكلمة المفتاحية func واسم الطريقة.
func (receiver type) MethodName(parameters) (returnTypes) {
}
لا يمكنك تعريف طريقة إلا إذا كان نوع مستقبِلها معرّفًا في الحزمة نفسها التي تُعرَّف فيها الطريقة.
package person
type Person struct {
Name string
}
func (p Person) Greetings() string {
return fmt.Sprintf("Welcome %s!", p.Name)
}
يمكن استدعاء الطريقة المعرّفة على البنية عبر الترميز النقطي.
p := Person{Name: "Bronson"}
fmt.Println(p.Greetings())
// Output: Welcome Bronson!
لاحظ كيف استدعينا الطريقة Greetings() على النسخة p من Person.
إنه تمامًا مثل استدعائك للطرق في لغة برمجة كائنية التوجه.
تذكّر: الطريقة ليست سوى دالة لها وسيط مستقبِل. تساعد الطرق على تجنّب تعارض الأسماء، فلأن الطريقة مرتبطة بنوع مستقبِل معيّن، يمكنك استخدام اسم الطريقة نفسه مع أنواع مختلفة.
import "math"
type rect struct {
width, height int
}
func (r rect) area() int {
return r.width * r.height
}
type circle struct {
radius int
}
func (c circle) area() float64 {
return math.Pow(float64(c.radius), 2) * math.Pi
}
هناك نوعان من المستقبِلات: مستقبِلات القيم ومستقبِلات المؤشرات.
كل الطرق التي رأيناها حتى الآن لها مستقبِل قيمة، أي أنها تستقبل نسخة من القيمة التي تُمرَّر إلى الطريقة، ما يعني أن أي تعديل يجري على المستقبِل داخل الطريقة لا يراه المستدعي.
يمكنك تعريف طرق بمستقبِلات مؤشرات لتعديل القيمة التي يشير إليها المستقبِل.
يتم ذلك بوضع * قبل اسم النوع.
على سبيل المثال، مع النوع rect، يُعرَّف مستقبِل المؤشر بالشكل *rect.
وتكون هذه التعديلات مرئية أيضًا لمستدعي الطريقة.
type rect struct {
width, height int
}
func (r *rect) squareIt() {
r.height = r.width
}
r := rect{width: 10, height: 20}
fmt.Printf("Width: %d, Height: %d\n", r.width, r.height)
// Output: Width: 10, Height: 20
r.squareIt()
fmt.Printf("Width: %d, Height: %d\n", r.width, r.height)
// Output: Width: 10, Height: 10
ملاحظة: هذا التمرين تكملة لتمرين need-for-speed.
في هذا التمرين ستُنظّم سباقات بين أنواع مختلفة من سيارات التحكم عن بُعد. لكل سيارة سرعتها وخصائص استهلاكها للبطارية الخاصة بها.
تبدأ السيارات ببطارية ممتلئة بالكامل (100%). في كل مرة تقود فيها السيارة باستخدام جهاز التحكم عن بُعد، تقطع مسافة تساوي سرعة السيارة بالأمتار، وتخفض نسبة البطارية المتبقية بمقدار معدل استهلاكها للبطارية.
إذا انخفضت بطارية السيارة عن نسبة استهلاكها للبطارية، فلن تتمكن من قيادتها بعد ذلك.
تحتوي سيارة التحكم عن بُعد على شاشة LED أنيقة تعرض معلومتين:
"Driven <METERS> meters"."Battery at <PERCENTAGE>%".لكل مضمار سباق مسافته الخاصة. تُختبر السيارات من خلال التحقق مما إذا كانت قادرة على إنهاء المضمار دون نفاد بطاريتها.
نفّذ الطريقة Drive على الصنف Car بحيث تُحدّث عدد الأمتار المقطوعة بناءً على سرعة السيارة، وتخفض البطارية وفقًا لمعدل استهلاكها للبطارية:
speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
car.Drive()
// car is now Car{speed: 5, batteryDrain: 2, battery: 98, distance: 5}
ملاحظة: لا تحاول قيادة السيارة إذا كان ذلك سيؤدي إلى انخفاض بطاريتها عن 0.
نفّذ الطريقة DisplayDistance على Car بحيث تُرجع المسافة كما تظهر على شاشة LED على هيئة string:
speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
fmt.Println(car.DisplayDistance())
// Output: "Driven 0 meters"
نفّذ الطريقة DisplayBattery على Car بحيث تُرجع نسبة البطارية كما تظهر على شاشة LED على هيئة string:
speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
fmt.Println(car.DisplayBattery())
// Output: "Battery at 100%"
لإنهاء سباق، يجب أن تكون السيارة قادرة على قطع مسافة السباق.
وهذا يعني ألّا تنفد بطاريتها قبل عبور خط النهاية.
نفّذ الطريقة CanFinish التي تأخذ trackDistance int كمعامل لها وتُرجع true إذا كانت السيارة قادرة على إنهاء السباق، وإلا فتُرجع false:
speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
trackDistance := 100
car.CanFinish(trackDistance)
// => true
سجّل في Exercism لتتعلّم وتتقن Go عبر 34 مفهومًا166 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.