الوحدة 1 · لغة Swift
الثوابت والمتغيّرات والأنواع
12 دقراءة 3 داختر بحكمة
الدرس في لمحة
عرّف الثوابت والمتغيّرات، واقرأ الأنواع التي تستنتجها Swift لك، واختر نوع الأرقام المناسب للمال في Pocket Budget.
لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.
أراجع كل عام كودًا كتبه مطوّرو iOS جدد، وأغلب تقارير الأعطال تعود إلى العادات القليلة نفسها: قيم تتغيّر حين لم يتوقّع أحد ذلك، وأرقام تفقد دقّتها بصمت، وافتراضات كان بإمكان الـ compiler (المترجِم) أن يكتشفها. صُمّمت Swift لتلتقط هذه الأخطاء بالتحديد، لكن بشرط أن تعمل مع نظام الأنواع لا أن تلتفّ عليه.
خلال هذه الدورة ستبني Pocket Budget، تطبيق iPhone صغيرًا يتتبّع ما تنفقه. يبدأ هنا بعدد قليل من القيم داخل playground في Xcode، وينتهي تطبيقًا بـ SwiftUI على TestFlight. لتتابع معي، افتح Xcode، واختر File › New › Playground، ثم اختر القالب Blank، واكتب الأمثلة. الـ playground (ملف التجارب) يشغّل الكود وأنت تكتبه ويعرض نتيجة كل سطر في الشريط الجانبي.
let وvar
في Swift طريقتان لتسمية قيمة. let تعرّف ثابتًا يُسنَد مرة واحدة. وvar تعرّف متغيّرًا يمكن أن يتغيّر.
let monthlyLimit = 1500
var spentSoFar = 0
spentSoFar = spentSoFar + 42
spentSoFar += 18 // shorthand for the line above
// monthlyLimit = 2000 // error: cannot assign to value: 'monthlyLimit' is a 'let' constantاستخدم let افتراضيًا. حين تكون القيمة ثابتة، لن تتساءل أبدًا من الذي غيّرها. وإن احتجت إلى تغييرها لاحقًا، يخبرك الـ compiler بذلك، ويعرض عليك Xcode إصلاحًا بنقرة واحدة يحوّل let إلى var. وفي الاتجاه المعاكس، يحذّرك Xcode حين لا يتغيّر var أبدًا. تعامل مع هذا التحذير كطلب لترتيب الكود.
استنتاج النوع
لم تكتب نوعًا واحدًا في المثال السابق، ومع ذلك لكل قيمة نوع (type). Swift تستنتج النوع من أول قيمة تسندها:
let category = "Coffee" // String
let cups = 3 // Int
let pricePerCup = 4.5 // Double
let isRecurring = false // Boolاضغط Option مع النقر على أي اسم في Xcode لترى نوعه المستنتَج. ويمكنك أيضًا أن تكتب النوع بنفسك عبر تحديد صريح للنوع (type annotation)، وهذا مفيد حين تختار القيمة المكتوبة وحدها النوع الخطأ:
let fee: Double = 3 // without the annotation, 3 would be an Intمتى أخذت القيمة نوعًا احتفظت به. لا يمكنك أن تضع String داخل cups لاحقًا. وهذا ما يجعل كود Swift مقروءًا بعد أشهر: الاسم يعني نوعًا واحدًا من الأشياء، إلى الأبد.
لا تحويلات صامتة
هذا هو السطر الذي يفاجئ القادمين من JavaScript أو Python:
let cups = 3
let pricePerCup = 4.5
// let total = cups * pricePerCup // error: binary operator '*' cannot be applied to operands of type 'Int' and 'Double'
let total = Double(cups) * pricePerCup // 13.5لا تحوّل Swift قيمة Int إلى Double (أو العكس) من وراء ظهرك. أنت تكتب التحويل، فيراه القارئ. وتحويل Double إلى Int بالكتابة Int(13.5) يحذف الكسر ويعطي 13، وهذا بالضبط نوع القرارات التي تريدها ظاهرة أثناء مراجعة الكود.
المال ليس Double
النوع Double فاصلة عائمة ثنائية. هو سريع ومثالي للمسافات أو توقيت الحركات، لكنه لا يستطيع تخزين معظم الكسور العشرية بدقة. أضف عشرة سنتات عشر مرات وانظر إلى النتيجة:
import Foundation
var withDouble = 0.0
var withDecimal: Decimal = 0
for _ in 1...10 {
withDouble += 0.1
withDecimal += 0.1
}
print(withDouble) // 0.9999999999999999
print(withDecimal) // 1تطبيق ميزانية يقول إنك أنفقت $0.9999999999999999 يفقد ثقة المستخدم فورًا. أما Decimal، القادم من Foundation، فيخزّن أرقامًا بالنظام العشري، فتبقى السنتات دقيقة. يستخدم Pocket Budget النوع Decimal لكل مبلغ، وستراه في معظم الدروس من الآن فصاعدًا.
لكن انتبه إلى أمر واحد: القيمة الكسرية المكتوبة مباشرة مثل let tip: Decimal = 0.07 تُقرأ أولًا على أنها Double ثم تُحوَّل، فقد تصل بالشكل 0.07000000000000001024. المبالغ القصيرة في الأمثلة مثل 4.5 أو 12.99 تمرّ سليمة، أما المبالغ التي تهمّ فعلًا فابنِ الـ Decimal فيها من نص (Decimal(string: "0.07")) أو من عدد السنتات الصحيح (Decimal(7) / 100).
صار لديك الآن ثوابت ومتغيّرات والأنواع التي خلفها. في الدرس التالي تتعرّف على النوع الذي جعل Swift مشهورة بالأمان: الـ optional، وهو طريقة Swift لتقول «قد لا توجد قيمة هنا».
أهم النقاط
- استخدم
letافتراضيًا، ولا تنتقل إلىvarإلا عندما يخبرك الـ compiler أن القيمة يجب أن تتغيّر. - تستنتج Swift النوع من أول قيمة تسندها، ولا يتغيّر هذا النوع بعد ذلك أبدًا.
- لا تحوّل Swift بين
IntوDoubleبصمت؛ أنت من يكتب التحويل صراحةً، فلا تفاجئك العمليات الحسابية بين نوعين مختلفين. - خزّن المال بالنوع
DecimalلاDouble، لأن الفاصلة العائمة الثنائية لا تستطيع تمثيل معظم السنتات بدقة.