Swift — بطل غير متوقع في البرمجة النظامية
\n\nعندما تسمع "البرمجة النظامية"، عادةً ما يتبادر إلى الذهن C القاسي، أو لغة التجميع، أو على الأقل Rust. Swift؟ نفس اللغة المستخدمة في تطبيقات الهواتف المحمولة الجميلة؟ اتضح أن الإجابة هي نعم. وهذه ليست مزحة.
\n\nلقد استثمرت Apple في Swift ليس فقط الراحة والأمان، بل أيضًا التحكم الكامل في الذاكرة والمؤشرات والاستدعاءات النظامية. في هذه المقالة، سنشرح كيف يمكن أن تصبح Swift أداتك الرئيسية لكتابة الأدوات المساعدة، وبرامج التشغيل، وبرامج الشبكات الخلفية، وحتى مكونات نظام التشغيل. استعد للدهشة — سيكون الكود حقيقيًا، عمليًا، ومثيرًا للاهتمام للغاية.
\n\nلماذا Swift؟ ثلاثة أركان للبرمجة النظامية
\n\nتتطلب البرمجة النظامية ثلاثة أشياء: الأداء، والتحكم في الموارد، والقدرة على العمل "قريبًا من العتاد". يوفر Swift كل هذا، بالإضافة إلى بعض المزايا الإضافية.
\n\n- \n
- أداء على مستوى C. يقوم المترجم LLVM بتحسين الكود ليس أقل من C أو C++. في اختبارات الأداء، غالبًا ما يتفوق Swift على Go و Rust في مهام الإدخال/الإخراج. \n
- وصول مباشر للذاكرة. من خلال آلية UnsafePointer و UnsafeMutablePointer والتعامل مع البايتات الخام. \n
- مكتبة قياسية غنية. لا حاجة لسحب مجموعة من التبعيات — كل ما يلزم للعمل مع المقابس والملفات والعمليات موجود بالفعل. \n
ومع ذلك، يظل Swift آمنًا: إذا لم تستخدم كتل unsafe، فسيحميك المترجم من تجاوز سعة المخزن المؤقت والمؤشرات المعلقة. وعندما تحتاج إلى ذلك — فقط اكتب withUnsafePointer وستحصل على تحكم كامل.
التعامل مع الذاكرة: من البايتات إلى الهياكل
\n\nلنبدأ بالأساسيات — التعامل مع الذاكرة الخام. تخيل أنك بحاجة إلى قراءة ملف ثنائي وتفسيره كمصفوفة من الهياكل. في C، كنت ستعاني مع malloc و sizeof. في Swift — بشكل أنيق وآمن.
\n\nقراءة ملف ثنائي في Swift
\n\nimport Foundation\n\nstruct Header {\n let magic: UInt32\n let version: UInt16\n let count: UInt16\n}\n\nfunc readBinaryFile(path: String) -> Header? {\n let data = try? Data(contentsOf: URL(fileURLWithPath: path))\n guard let data = data else { return nil }\n \n return data.withUnsafeBytes { (ptr: UnsafeRawBufferPointer) in\n guard let baseAddress = ptr.baseAddress else { return nil }\n let headerPtr = baseAddress.assumingMemoryBound(to: Header.self)\n return headerPtr.pointee\n }\n}\n\nلاحظ: نحن لا نخصص الذاكرة يدويًا. يوفر withUnsafeBytes مؤشرًا مؤقتًا يعيش فقط داخل الإغلاق. هذا آمن وفعال ويُقرأ مثل النثر الجيد.
إنشاء الهياكل والتعامل مع المؤشرات
\n\nماذا لو كنت بحاجة إلى إنشاء هيكل في الذاكرة وتمرير عنوانه إلى استدعاء نظامي؟ بسهولة!
\n\nstruct sockaddr_in {\n var sin_len: UInt8 = 0\n var sin_family: UInt8 = UInt8(AF_INET)\n var sin_port: in_port_t = 0\n var sin_addr: in_addr = in_addr(s_addr: 0)\n var sin_zero: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) = (0,0,0,0,0,0,0,0)\n}\n\nvar address = sockaddr_in()\naddress.sin_port = CFSwapInt16HostToBig(8080)\naddress.sin_addr.s_addr = inet_addr("127.0.0.1")\n\nlet ptr = withUnsafePointer(to: &address) { $0 }\nlet rawPtr = UnsafeRawPointer(ptr)\n\nهذا الكود هو الأساس للعمل مع المقابس على مستوى منخفض. نحن نحدد الهيكل يدويًا، ونملأ الحقول، ونحصل على مؤشر خام لتمريره إلى connect أو bind.
الاستدعاءات النظامية وواجهة POSIX API
\n\nيتوافق Swift بشكل ممتاز مع POSIX. يمكنك استدعاء open و read و write و fork و exec — كل شيء كما في الأيام الخوالي، ولكن بتركيب لغوي من القرن الحادي والعشرين.
إنشاء fork + exec في Swift
\n\nimport Darwin\n\nfunc spawnProcess(path: String, args: [Str