المسارات
/
Go
Go
/
التمارين
/
الحاجة إلى السرعة
الحاجة إلى السرعة

الحاجة إلى السرعة

تمرين تعلّمي

مقدمة

في Go، struct هو تسلسل من عناصر مسماة تُسمى الحقول، ولكل حقل اسم ونوع. ويجب أن يكون اسم الحقل فريدًا داخل struct. ويمكن مقارنة struct بـ الأصناف في نمط البرمجة كائنية التوجّه.

تعريف struct

تُنشئ struct جديدة باستخدام الكلمتين المفتاحيتين type و struct، وتحدّد اسم الحقول ونوعها صراحةً. على سبيل المثال، نعرّف هنا struct تُسمى Shape، وهي تحمل اسم شكل وحجمه:

type Shape struct {
    name string
    size int
}

تتبع أسماء الحقول في struct اصطلاح Go: فالحقول التي يبدأ اسمها بحرف صغير لا تكون مرئية إلا للكود الموجود في الحزمة نفسها، أما الحقول التي يبدأ اسمها بحرف كبير فتكون مرئية في الحزم الأخرى.

إنشاء نسخ من struct

بعد أن تُعرّف struct، تحتاج إلى إنشاء نسخة جديدة تحدّد فيها الحقول باستخدام أسماء الحقول وبأي ترتيب:

s := Shape {
    name: "Square",
    size: 25,
}

لقراءة حقول النسخة أو تعديلها، استخدم ترميز النقطة .:

// Update the name and the size
s.name = "Circle"
s.size = 35
fmt.Printf("name: %s size: %d\n", s.name, s.size)
// Output: name: Circle size: 35

الحقول التي لم تُسنَد إليها قيمة أولية ستأخذ قيمتها الصفرية. على سبيل المثال:

s := Shape{name: "Circle"}
fmt.Printf("name: %s size: %d\n", s.name, s.size)
// Output: name: Circle size: 0

يمكنك إنشاء نسخة من struct دون استخدام أسماء الحقول، ما دمت تحدّد الحقول بالترتيب:

s := Shape {
	"Oval",
	20,
}

غير أن هذا التركيب يُعدّ كودًا هشًا، لأنه قد يتعطل عند إضافة حقل، خصوصًا إذا كان الحقل الجديد من نوع مختلف. في المثال التالي، نضيف حقلًا إضافيًا إلى Shape:

type Shape struct {
	name        string
	description string // new field 'description' added
	size        int
}

s := Shape{
    "Circle",
    20,
}
// Since the second field of the struct is now a string and not an int,
// the compiler will throw an error when compiling the program:
// Output: cannot use 20 (type untyped int) as type string in field value
// Output: too few values in Shape{...}

دوال New

أحيانًا يكون من الجيد أن تكون لدينا دوال تساعدنا في إنشاء نسخ من struct. بحسب الاصطلاح، تُسمى هذه الدوال عادةً New أو تبدأ أسماؤها بـ New، ولكن لأنها مجرد دوال عادية، يمكنك أن تمنحها أي اسم تريد. قد تذكّرك بالدوال المنشئة في لغات أخرى، لكنها في Go ليست سوى دوال عادية.

في المثال التالي، تُستخدم إحدى دوال New لإنشاء نسخة جديدة من Shape وتعيين قيمة افتراضية للحقل size في الشكل تلقائيًا:

func NewShape(name string) Shape {
	return Shape{
		name: name,
		size: 100, //default-value for size is 100
	}
}

NewShape("Triangle")
// => Shape { name: "Triangle", size: 100 }

قد يكون لاستخدام دوال New المزايا التالية:

  • التحقق من القيم المعطاة
  • التعامل مع القيم الافتراضية
  • بما أن دوال New تُعرَّف غالبًا في الحزمة نفسها التي تحتوي على struct التي تهيّئها، فيمكنها تهيئة الحقول الخاصة في struct أيضًا

التعليمات

في هذا التمرين ستنظّم سباقات بين أنواع مختلفة من السيارات التي يتم التحكم فيها عن بُعد. ولكل سيارة سرعتها وخصائص استهلاكها للبطارية.

تبدأ السيارات ببطارية ممتلئة بالكامل (100%). وفي كل مرة تقود فيها السيارة باستخدام جهاز التحكم عن بُعد، تقطع مسافة تساوي سرعة السيارة بالأمتار، وينخفض ما تبقى من نسبة البطارية بمقدار استهلاك البطارية.

إذا انخفضت بطارية السيارة إلى ما دون نسبة استهلاك البطارية، فلن تتمكن من قيادتها بعد ذلك.

لكل مضمار سباق مسافة خاصة به. ويُختبر كل سيارة بالتحقق مما إذا كانت قادرة على إنهاء المضمار دون أن تنفد بطاريتها.

1. أنشئ سيارة يتم التحكم فيها عن بُعد

عرّف بنية Car بالحقول التالية من النوع int:

  • battery
  • batteryDrain
  • speed
  • distance

ولإنشاء سيارة يتم التحكم فيها عن بُعد، عرّف دالة NewCar تأخذ سرعة السيارة بالأمتار، ونسبة استهلاك البطارية كمعاملين لها (كلاهما من النوع int) وتُرجع نسخة من Car:

speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
// => Car{speed: 5, batteryDrain: 2, battery:100, distance: 0}

2. أنشئ مضمار سباق

عرّف نوع بنية آخر باسم Track يحتوي على الحقل distance من نوع عدد صحيح. ولإنشاء مضمار سباق، عرّف دالة NewTrack تأخذ مسافة المضمار بالأمتار كمعامل وحيد لها (وهو من النوع int):

distance := 800
track := NewTrack(distance)
// => Track{distance: 800}

3. قُد السيارة

نفّذ دالة Drive التي تحدّث عدد الأمتار المقطوعة بناءً على سرعة السيارة، وتُخفض البطارية وفقًا لمقدار استهلاكها. وإذا لم تكن البطارية كافية للقيادة مرة أخرى، فلن تتحرك السيارة:

speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
car = Drive(car)
// => Car{speed: 5, batteryDrain: 2, battery: 98, distance: 5}

4. تحقق مما إذا كانت سيارة يتم التحكم فيها عن بُعد قادرة على إنهاء السباق

لكي تُنهي السيارة سباقًا، يجب أن تكون قادرة على قطع مسافة السباق. وهذا يعني ألا تنفد بطاريتها قبل أن تعبر خط النهاية. نفّذ دالة CanFinish التي تأخذ نسخة من Car ونسخة من Track كمعامل لها وتُرجع true إذا كانت السيارة قادرة على إنهاء السباق؛ وإلا فلتُرجع false.

افترض أنك الآن عند خط بداية السباق وأنك شغّلت محرك السيارة للسباق. وضع في اعتبارك أن بطارية السيارة قد لا تكون ممتلئة بالكامل عند بدء السباق:

speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)

distance := 100
track := NewTrack(distance)

CanFinish(car, track)
// => true
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
Go Exercism

مستعد لبدء الحاجة إلى السرعة؟

سجّل في Exercism لتتعلّم وتتقن Go عبر 34 مفهومًا165 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.