أمل عبدالله محمد الجنايني

الأعضاء
  • المساهمات

    6
  • تاريخ الانضمام

  • تاريخ آخر زيارة

السُّمعة بالموقع

0 Neutral
  1. هل تحتاج إلى تطبيق في متجر التطبيقات؟ هل يجب أن تكون أصلية (Native) أم مُهجّنة (Hybrid)؟ ما الفرق بين تطبيق جوال وتطبيق ويب وموقع متجاوب؟ هل تعتقد أن يكون الموقع متجاوبًا (Responsive Website)، فهذا يجعله متوافقًا مع الجوال (Mobile Friendly)؟ كل هذه الاسئلة عليك أن تُجيب عنها إذا ما أردت التعامل مع الأجهزة المحمولة كمُطوِّر، وهذا ما سنسلط عليه الضوء في هذا المقال. أنواع تطبيقات الجوال هناك الكثير من الالتباس بين المؤسسات حول كيفية التعامل مع الأجهزة المحمولة. ومع ذلك، عندما يتعلق الأمر بهذا فلديك 4 خيارات كالتالي: التطبيقات الأصلية أو الأصيلة (Native Applications). تطبيقات الويب (Web Application). التطبيقات المُهجّنة (Hybird Application). المواقع المُتجاوبة (Responsive Websites). التطبيقات الأصلية (Native Applications) التطبيقات الأصلية هي تطبيقات تعمل فعليًا على الجهاز المحمول ويتم ترميزها خصيصًا لنظام تشغيل الجهاز. هذه هي التطبيقات التي تجدها عادةً في متجر تطبيقات Google Play أو iOS. هذا هو أفضل نهج حيث السرعة والميزات الأصلية (Native Features) مطلوبة. تطبيقات الويب (Web Application) هناك خصائص مشتركة بين كلٍ من تطبيقات الويب، التطبيقات الأصلية، والمواقع المُتجاوبة. كما هو الحال مع الموقع المتجاوب، تُصمَّم تطبيقات الويب باستخدام HTML و CSS و Javascript ويكون بالكامل على الإنترنت. ومع ذلك، عندما يكون الموقع المُتجاوب موجَّهًا للمحتوى (Content Oriented)، فإن تطبيق الويب يركز على المهمة بنفس طريقة التطبيق الأصلي. ومن الأمثلة على ذلك تطبيق Blackpool Pleasure Beach للهاتف المحمول. التطبيق متاح عبر الإنترنت ولكنه ليس موقع ويب غني بالمحتوى. بدلاً من ذلك، إنه تطبيق حجز يسمح للمستخدمين بشراء تذاكرهم وبطاقاتهم. نظرًا لأنه يتطلب اتصالًا مستمرًا بالخادم(Server)، ولم يستخدمه المستخدمون بشكل منتظم ولا يحتاج إلى ميزات أصلية، فلا فائدة من جعله تطبيقًا أصليًا. التطبيقات الهجينة (Hybird Application) ربما يكون التطبيق المُهجّن أو الهجين هو الأصعب في شرح الخيارات. يُعَد التطبيق المُهجّن تطبيقًا أصليًا أُنشئ باستخدام HTML و CSS و Javascript. فمن خلال بناء هذه التطبيقات باستخدام تقنية الويب، يكون تطويرها أسرع وأسهل للنشر على منصات متعددة (مثل iOS أو Android). الجانب السلبي هو أن الأداء لا يميل إلى أن يكون جيدًا ويفتقر إلى نمط التصميم لكل منصة. مثال على هذا النوع من التطبيقات هو إثبات مفهوم تطبيق "فراشة العد butterfly counting" الذي طوّرته Headscape. تم بناء هذا التطبيق المُهجَّن في PhoneGap وسمح للمستخدمين بتحديد وحساب الفراشات في الحقل حتى مع عدم وجود اتصال بالانترنت. كان قرار إنشاء هذا كتطبيق هجين لأنه إثباتًا للمفهوم وأرادت الشركة إنتاجه بسرعة وبأقل تكلفة. المواقع المتجاوبة (Responsive Websites) الموقع المُتجاوب هو الذي يتكيف مع أي جهاز يتم عرضه عليه. سواء كان ذلك عبارة عن جهاز سطح مكتب أو جهاز لوحي أو جهاز محمول، سيعرض موقع الويب نفسه المحتوى نفسه باستخدام تصميم مرئي يناسب هذا الجهاز. خذ على سبيل المثال Macmillian English. فهو موقعٌ غنيٌّ جدًا بالمعلومات. يُنقِّب مستخدمو الموقع عن المعلومات بدلاً من إتمام المهام. يضمن موقع الويب المتجاوب أن يتمكنوا من العثور على نفس المعلومات مهما كان الجهاز الذي يستخدمونه. المواقع المُتجاوبة جيدة لـ : المواقع الغنيّة بالمعلومات. المستخدمين الذين يتطلعون إلى جمع المعلومات. إذا كنت لست متأكدًا من الخيار الذي تحتاجه، فعادةً ما يكون الموقع المُتجاوب نقطة انطلاقٍ جيدة. هذا ما نعتقده عادًًة، أن تكون المواقع مُتجاوبة، فهذا يجعلها متوافقة مع الجوال (Mobile Friendly)، لكن هذا ليس كل ما في الأمر. لا تزال هناك طرق كثيرة تُمكّننا من إفساد تجربة المُستخدم والإضرار بموضعنا في نتائج البحث. ألق نظرة على دورة تطوير تطبيقات الجوال باستخدام تقنيات الويب والتي ستتعلم فيها تطوير تطبيقات جوال لأنظمة أندرويد وأيفون و ويندوز فون باستخدام تقنيات الويب البسيطة JavaScript, HTML, CSS مما يمكنك من تطوير تطبيق واحد يعمل مباشرة على جميع المنصات. إنشاء موقع متجاوب متوافق تمامًا مع الجوال ندرك جيدًا أهمية أن يكون الموقع متوافقًا مع الجوال، ويميل معظمنا إلى التفكير في "التصميم المتجاوب Responsive Website" كحل لهذا. لا ريب أن "التصميم المُتجاوب" قد أحدث طفرةً في تطبيقات الويب على الهواتف الذكيّة. فبوجٍه عام، لقد حسّنَ "تجربة المُستخدم User Experience" وسهّل علينا إدارة المواقع وجنّبنا الحفاظ على إصدارات متعددة لنفس الموقع. دعني أقدم لك بعض الأمثلة عن "أين يمكن أن تسوء الأمور" بدءًا من المشكلة الأكبر على الإطلاق "المواقع شبه المتجاوبة". هل موقعك مُتجاوب بالكامل؟ عندما نقوم بإعادة تصميم موقع ويب من البداية، فإن بناءه حيث يصبح "موقعًا متجاوبًا" أمرًا منطقيًا تمامًا. لكن تعديل لموقع موجود بالفعل (خاصةً إذا كان موقعًا كبيرًا) حيث يصبح "موقعًا متجاوبًا"، يمكن لهذا أن يتحول إلى كابوس. العديد من العملاء واجهوا هذه المشكلة، تحتوي معظم المواقع الإلكترونية الخاصة بهم على عشرات الآلاف من الصفحات على الأقل، تم إنشاؤها على مدار سنوات. مما جعل أمر أن تكون هذه المواقع "صديقة للهواتف الذكيّة" تحديًا بشكل لا يُصدَّق. لتقليل العمل الذي ينطوي عليه الأمر، فهم يتخذون قرارًا بالتركيز على الصفحات الأساسية وجعلها سهلة الاستخدام على الهواتف الذكيّة ومٌتجاوبة أيضًا، متجاهلين البقية. بالرغم من أنني أستطيع فهم هذا القرار إلا أنه سيء جدًا من منظور "تجربة المستخدم". ليس هناك ما هو أكثر إحباطًا من التورط في التفكير بأنّك تتصفح موقعًا صديقًا للهاتف، فقط لتجد نفسك عالقًا في صفحة مُحسّنة لسطح المكتب لا يمكنك قراءتها أو تصفّحها. تحتاج هذه المنظمات إلى التفكير بتمعن ولفترة طويلة حول ما إذا كانت تحتاج لمثل هذه المواقع الكبيرة. من واقع خبرتي، نادرًا ما يقومون بذلك، ويقومون فقط بترحيل المحتوى بشكلٍ أعمى من إصدارٍ لآخر. هل قلصت وظائفية الموقع؟ يواجه المصممون مشكلة مماثلة عندما يصطدمون ببعض الوظائف الشاقة للموقع. شيء يبدو معقدًا جدًا لدرجة لا تمكّنه من صداقة الهواتف المحمولة ويكون التعامل مع الموقع على الهاتف شاقًا جدًا على المُستخدم. بدلًا من مضاعفة الجهود والتوصل لحل مُبتكر، نسهل الطريق الأقل صعوبة ومقاومة. نحن نقنع أنفسنا بأن مُستخدمي الهواتف لن يحتاجوا إلى هذه الوظائف وسيُزيلونها من الموقع. هذا بالطبع، أمرٌ ساذج بشكل لا يُصدّق. لا يختلف مُستخدمو الهواتف المحمولة بطريقة سحرية. هم نفس المُستخدمين الذين يستخدمون موقعك على "سطح المكتب Desktop". لقد بدّلوا الأجهزة فقط. لقد رأيتُ حتى أن الناس يستخدمون الهواتف المحمولة أثناء الجلوس في متناول اليد من أجهزة الحاسوب الخاصة بهم. لا يمكننا وضع افتراضات حول متطلباتهم بناءً على الجهاز. هل تؤيد إشارات اللمس؟ لا تتعلق الأخطاء الصديقة لأجهزة الهاتف فقط بإزالة الأشياء، يمكن أن يكون الفشل في إضافة شيء ما بنفس الخطورة. خذ على سبيل المثال "دعم إشارات اللمس". لا عجب أن كثيرًا من المُستخدمين يفضلون أحيانًا تطبيقات الأجهزة المحمولة عندما لا يُمكنهم التحرك والضغط على موقع إلكتروني على الهاتف. يجب حقًا على مصممي المواقع السماح للمستخدمين بتحريك الصور الدائرية والضغط عليها. فغالبًا ما يتم التغاضي عن هذا النوع من الوظائف لأننا نركز على تكييف التصميم لنقاط التوقف المختلفة. هل يتكيف المحتوى وكذلك التصميم؟ أن يكون الموقع صديقًا للهاتف المحمول، فهذا لا يعني تغيير التصميم فقط، إنّه يتعلق أيضًا بتغيير المحتوى نفسه. خذ "الجدول" على سبيل المثال. فقط لأننا نعرض البيانات كجدول بأحجام شاشات أكبر، فهذا لا يعني أن علينا أن نفعل ذلك على الهواتف أيضًا. قد نستنتج أن عرض "مخطط تفاعلي interactive chart" أو شكل من أشكال الآلة الحاسبة أكثر صداقة للهاتف "Mobile Friendly". نحتاج إلى تعديل المحتوى وليس فقط التصميم والجداول ومخططات المعلومات البيانية، إلى شيء يسهل التعامل معه على الهاتف ثم يأتي دور "الرسوم البيانية infographics"، التي تبدو رائعة على الشاشات الكبيرة لكنها تصبح غير قابلة للقراءة على أجهزة الهاتف. نستطيع بالتأكيد أن نسمح للمُستخدم بتكبير الشاشة وندّعي بذلك أننا قمنا بعملنا على أكمل وجه، أو يمكننا أن نعيد تخيلهم. ربما يجب علينا أن نُقسِّم هذه الرسوم البيانية إلى "لوحة رسوم Storyboard" أو نستخدم فيديو عوضًا عن ذلك. هل موقعك مقروءًا على الهاتف بقدر الإمكان؟ لا تقتصر مشاكل الوضوح فقط على الصور والجداول، إنما ينطبق الأمر بنفس القدر على النص. لن تُخلق تجربة ودية ومقروءة مع الهاتف بمجرد إضافة نقاط توقف إلى عناصر إعادة الموضع. انها غالبًا ما تُقصِّر أطوال الخطوط لدرجة تجعل القراءة صعبة للغاية. يبذل المصممون جهدًا في هذا الصدد بجعل حجم الخط يتناسب مع نقطة التوقف (breakpoint)، وبتقليص حجمه وفقًا لذلك. لكنني زرتُ العديد من المواقع على الأجهزة المحمولة حيث أصبحت أحجام الخطوط صغيرة جدًا مما يجعل النص غير مقروء. وأخيرًا، هناك قضية "اللون". غالبًا ما يفشل المصممون في أن يأخذوا بعين الاعتبار وهج الشاشة التي يعاني منها مستخدمو الهواتف المحمولة، ومن ثَمَّ يصنعون لوحات الألوان الدقيقة التي تُصعِّب تجربة القراءة على الهاتف وهذا على أقل تقدير. هل تركز بشكل كبير على أحدث وأفضل الهواتف الذكيّة؟ بالطبع، بعض مشاكل الوضوح هذه غير مرئية لنا حتى عند اختبارها على جهاز محمول. ذلك لأن لدينا أحدث وأكبر هاتف ذكي. إنه يحتوي على شاشة شبكية (retina screen)، ذات دقة عالية جدًا، وسطوع لا يمكن حتى للشمس أن تجاريها! ولكن ليس الجميع لديه أجهزة كهذه. حتى لو تجاهلت الهواتف المميزة كبندٍ للمقارنة، فقد تختلف التجارب بشكل كبير. ثم، بالطبع، هناك نقاط توقف. ما زلت أرى أن المصممين يقومون بتعيين نقاط التوقف استنادًا على الجهاز، بدلًا من المكان المناسب في المحتوى. لديهم تصميم بحجم iPad، وتصميم بحجم iPhone وما إلى ذلك. ولكن في الحقيقة، الأحجام متنوعة بشكل كبير، ونحتاج إلى التوقف عن التفكير في أجهزة معينة. هل أداؤك صديقًا للهاتف؟ الأداء هو ما يجب أن نفكر به. في الواقع، ربما تكون هذه هي المنطقة الأكبر الوحيدة حيث يخذلنا "التصميم المتجاوب". لا تسيئ فهمي أنا لا أقول أن "التصميم المتجاوب" يجعل مواقعنا أبطأ. إنه فقط لا يفعل شيئًا لتحسينه وهو شيء تحتاجه الأجهزة المحمولة. حجم الصورة بالتأكيد هو السبب. قد يؤدي استخدام "استعلامات الوسائط media queries" إلى تصغير الصورة بصريًا، لكنه لن يؤثر في تقليل حجم الصورة أو أوقات التحميل. هذا ليس جيدًا عند استخدام شبكة خلوية. أضف إلى ذلك الخطوط والمكتبات والأطر وجميع العناصر الأخرى التي تنتفخ في مواقع الويب الحالية ولديك أوقات تحميل سيئة. يمكن أن يؤدي اختبار أداء موقعك على الأجهزة المحمولة إلى قراءة محبطة! لكن هذه ليست مجرد مشكلة في حجم التنزيل وسرعة الشبكة الخلوية. الأداء هو مشكلة في الجهاز أيضًا. تفتقر العديد من الأجهزة المحمولة إلى قدرة معالجة أجهزة الحاسوب المحمولة أو أجهزة الحاسوب المكتبية أو الأجهزة اللوحية. والنتيجة هي أنها لا تستطيع التعامل مع قالب مُكثف من كود الجافاسكريبت "intensive javascript" موجود على العديد من المواقع الحديثة. هل ملء البيانات سهلًا على الهواتف؟ بعد ذلك، نأتي إلى مجموعة معينة من الأخطاء تحدث عندما نقوم بإدخال البيانات على الأجهزة المحمولة. فهل لك أن تتخيل كيف يمكن لأحد إدخال كم كبير من البيانات عبر لوحة مفاتيح هاتفه الصغير خلال فترة زمنية قصيرة؟ الأمر مريع حقًا، خصوصًا إن كان المستخدم مسنًا. كمصممي ويب، يبدو أننا نجعل المشكلة أسوأ بمئة مرة على مواقع الويب. عند إدخال بيانات رقمية، نفشل في عرض لوحة مفاتيح رقمية. عند إدخال كلمات المرور، نخفي ما يكتبه المستخدم، على الرغم من حقيقة أن الأخطاء المطبعية أمرًا شائعًا على الأجهزة المحمولة. في الواقع، لا ينبغي لنا أن نتوقع من مستخدمي الجوال ملء كلمات المرور على الإطلاق. هناك العديد من البدائل الأخرى مثل الإشعارات النصية أو روابط البريد الإلكتروني أو "معرف اللمس Touch ID". هناك العديد من المواقف التي يمكن فيها تجنب إدخال البيانات أو تبسيطها. سيكون تذكر اسم المستخدم لتسجيل الدخول بين الجلسات بداية جيدة. ولكن يجب علينا أيضًا تحسين تصميم النموذج وتجنب عناصر الأشكال المملوءة مثل منتقي التواريخ أو القوائم المنسدلة الطويلة. هل الروابط معبأة بإحكام أيضًا؟ عند الحديث عن التفاعلات المزعجة، أشعر بالدهشة إزاء قلة الاهتمام الذي يبديه المصممون للتحديات المحيطة باستخدام شاشة تعمل باللمس. أجد أن العديد من مواقع الويب التي تدّعي أنها صديقة للهاتف، ليست كذلك عندما تبدأ بالتفاعل معها. غالبًا ما يتم تجميع الارتباطات والأزرار معًا لزيادة حجم الشاشة إلى الحد الأقصى، بحيث يصبح من المستحيل النقر عليها. مرةً أخرى، مجرد تغيير موضع المحتوى لا يكفي. نحتاج إلى ضمان أن المساحة حول العناصر تتّسع للسماح بنقص الدقة الذي يحدث جرّاء استخدام الإصبع. من المسلَّم به أن المساحة هي ميزة استثنائية، ولكن إذا استخدمنا المساحة المتوفرة لدينا بحكمة، فلا يوجد سبب يمنع اختيار الروابط بسهولة أكبر. فقط إلقِ نظرة على متوسط التطبيق المحمول الخاص بك. هل يتعين على المستخدمين تحمُّل محتوى ثابت الموضع؟ بالحديث عن قلة المساحة، لماذا على الرغم من رغبة جميع المصممين في إنشاء موقع ويب سهل الاستخدام للهاتف المحمول، فإننا نعتبر أنه من المقبول إضافة محتوى موقع ثابت إلى الصفحة. هذا يقلل بشكل كبير من المساحة المتاحة لعناصر المحتوى الأخرى. فكر بتمعُّن قبل نقل تنقلاتك الثابتة إلى منظور موقعك الإليكتروني على الهاتف. بالمثل، قم بإبعاد تلك الطبقات ونوافذ الحوار، وكذلك رموز مواقع التواصل الاجتماعي الثابتة. ليس لديهم مكان على موقع إليكتروني على الهاتف. يكاد يكون من المستحيل قراءة المحتوى الموجود على Mashable على جهاز محمول نظرًا لحجم عناصر الموضع الثابت. ما المناسب لك؟ كلٌ من الخيارات الأربعة التي تمت مناقشتها في هذا المنشور له مكانه المناسب الذي سيختلف بناءً على الاحتياجات الخاصة بك. ومع ذلك، فإن نقطة الانطلاق الجيدة هي السؤال عمّا إذا كان المستخدمون يقومون في المقام الأول بإكمال مهمة أو الوصول إلى المعلومات. إذا كان الوصول إلى المعلومات هو الهدف، فمن المؤكّد أنّ المواقع المُتجاوبة هي الحل الأمثل. أمّا اذا كان "إكمال مهمة" هو الهدف، فعليك أن تسأل عمّا إذا كانت السرعة أم الوصول إلى الميزات الأصلية أيهما أهم. إذا كان الأمر كذلك، فستحتاج إلى تطبيق أصلي أو مُهجّن، وإلاّ سيكون تطبيق الويب مثاليًا. ترجمة -وبتصرف- للمقالين Is your site as mobile friendly as you think و Mobile app vs mobile website design: Your four options لصاحبهما Paul Boag
  2. سنتعرف في هذا المقال على إيجابيات وسلبيات تخزين البيانات في Go باستخدام المصفوفات Arrays والشرائح Slices ولماذا يكون أحدها أفضل من الآخر عادةً. هذا المقال جزء من سلسلة Go التي كتبها Mihalis Tsoukalos: الجزء 1: إنشاء كلمات مرور عشوائية وآمنة في Go الجزء 2: بناء خادم TCP متزامن في لغة البرمجة Go. الجزء 3: 3 طرائق لنسخ الملفات في لغة البرمجة Go. المصفوفات Arrays تعد المصفوفات واحدةً من أكثر هياكل البيانات شيوعًا بين لغات البرمجة لسببين رئيسيين: إنّها بسيطة وسهلة الفهم، ويمكنها تخزين أنواع مختلفة من البيانات فيها. يمكنك تعريف مصفوفة Array في لغة البرمجة Go، تحت اسم anArray مثلًا والتي تُخزِّن أربعة أعداد صحيحة كما يلي: anArray := [4]int{-1, 2, 0, -4} يُحدَّد حجم المصفوفة Array Size أولًا، ثم نوعها Array Type، وأخيرًا عناصرها Array Elements. تُساعدك الدّالة ()len في معرفة طول المصفوفة فحجم المصفوفة السابقة هو 4. إذا كنت على درايةٍ بلغات برمجة أخرى، فقد حاولت الوصول لجميع عناصر المصفوفة باستخدام حلقة for. ومع ذلك، كما سترى لاحقًا، أنّ الكلمة المفتاحية range الخاصة بلغة Go تُتيح لك الوصول لجميع عناصر المصفوفة أو الشريحة بسلاسة. وأخيرًا، إليك كيفية تحديد مصفوفة ذات بُعدين two dimentional array: twoD := [3][3]int{ {1, 2, 3}, {6, 7, 8}, {10, 11, 12}} الملف المصدر arrays.go يُوضِّح كيفية استخدام مصفوفات Go، ها هو الكود الأكثر أهمية في ملف arrays.go: for i := 0; i < len(twoD); i++ { k := twoD[i] for j := 0; j < len(k); j++ { fmt.Print(k[j], " ") } fmt.Println() } for _, a := range twoD { for _, j := range a { fmt.Print(j, " ") } fmt.Println() } يوضح هذا كيف يُمكنك المرور على عناصر المصفوفة باستخدام for loop والكلمة المُفتاحية range. توضّح باقي الكود الخاص بالملف arrays.go كيفية تمرير المصفوفة كمعامل دالّة. فيما يلي هو ناتج arrays.go: $ go run arrays.go Before change(): [-1 2 0 -4] After change(): [-1 2 0 -4] 1 2 3 6 7 8 10 11 12 1 2 3 6 7 8 10 11 12 يوضح هذا الناتج أنّ التغييرات التي تُجريها على مصفوفة داخل دالة تُفقَد بعد إنتهاء الدالة. عيوب ومساوئ المصفوفات arrays لدى مصفوفات Go العديد من المساوئ التي لابد أن تأخذها بعين الإعتبار حينما تستخدمها في مشاريع Go. أولًا، لا يُمكنك تغيير حجم المصفوفة بعد تعريفها، وهذا يعني أنّ مصفوفات Go ليست ديناميكية. بعبارة أبسط، إذا كنت بحاجة إلى إضافة عنصر إلى مصفوفة مُمتلئة، ستحتاج إلى إنشاء مصفوفة أكبر ونسخ جميع عناصر المصفوفة القديمة إلى الجديدة. ثانيًا، عندما تقوم بتمرير مصفوفة إلى دالة كمعامل لهذه الدالة، فإنّك في الواقع تُمرر نسخة من المصفوفة، مما يعني أن أي تغييرات تُجريها على المصفوفة داخل الدالة ستُفقد بعد إنتهاء هذه الدالة. أخيرًا، يمكن أن يكون تمرير مصفوفة كبيرة إلى دالة بطيئًا جدًا، خاصة وأن Go يجب أن تنشئ نسخة من هذه المصفوفة. الحل لجميع هذه المشاكل هو استخدام الشرائح Slices التي توفرها Go. الشرائح Slices تشبه شرائح Go مصفوفات Go لكن بدون أوجه القصور. أولاً، يمكنك إضافة عنصر إلى شريحة موجودة باستخدام الدالة ()append، علاوةً على ذلك، تم تنفيذ شرائح Go داخليًا باستخدام المصفوفات، مما يعني أن Go تستخدم مصفوفةً أساسيًة لكل شريحة. الشرائح لها خاصية سعة وخاصية طول، وهما ليستا نفس الشيء دائمًا. طول الشريحة هو نفس طول المصفوفة التي تحتوي على نفس عدد العناصر، ويمكن معرفتها باستخدام الدالة ()len. أمّا سعة الشريحة فهي الغرفة التي تم تخصيصها حاليًا للشريحة، ويمكن معرفتها باستخدام الدالة ()cap. نظرًا لأن الشرائح ديناميكية الحجم، ففي حالة نفاذ شريحة ما (مما يعني أن الطول الحالي للمصفوفة هو نفس السعة أثناء محاولة إضافة عنصر آخر إليها)، يعمل نظام Go تلقائيًا على مضاعفة قدرته الحالية على توفير مساحة لمزيد من العناصر ويضيف العنصر المطلوب إلى المصفوفة. بالإضافة إلى ذلك، يتم تمرير الشرائح للدوال حسب المرجع (Pass by reference)، مما يعني أن ما يتم نقله فعليًا إلى الدالة هو عنوان الذاكرة لمتغير الشريحة ، ولن تضيع أي تعديلات تجريها على الشريحة داخل إحدى الدوال بعد انتهائها. نتيجةً لذلك، فإن تمرير شريحة كبيرة إلى دالة يكون أسرع بكثير من تمرير مصفوفة بنفس عدد العناصر إلى نفس الدالة. وذلك لأن Go لن تضطر إلى عمل نسخة من الشريحة، إذ إنها ستُمرِّر فقط عنوان ذاكرة متغير الشريحة. يتم توضيح شرائح Go في ملف slice.go، والذي يحتوي على الكود التالي: package main import ( "fmt" ) func negative(x []int) { for i, k := range x { x[i] = -k } } func printSlice(x []int) { for _, number := range x { fmt.Printf("%d ", number) } fmt.Println() } func main() { s := []int{0, 14, 5, 0, 7, 19} printSlice(s) negative(s) printSlice(s) fmt.Printf("Before. Cap: %d, length: %d\n", cap(s), len(s)) s = append(s, -100) fmt.Printf("After. Cap: %d, length: %d\n", cap(s), len(s)) printSlice(s) anotherSlice := make([]int, 4) fmt.Printf("A new slice with 4 elements: ") printSlice(anotherSlice) } الفرق الأكبر بين تعريف الشريحة وتعريف المصفوفة هو أنّك لست بحاجة إلى تحديد حجم الشريحة، والذي يتم تحديده بعدد العناصر التي تريد وضعها فيها. بالإضافة إلى ذلك، تتيح لك الدالة ()append إضافة عنصر إلى شريحة موجودة؛ لاحظ أنه حتى إذا كانت سعة الشريحة تسمح لك بإضافة عنصر إلى هذه الشريحة فلن يتم تعديل طولها ما لم تستخدم ()append. الدالة ()printSlice هي دالة مُساعدة، تُستخدم لطباعة عناصر معامل الشريحة الخاص بها، في حين أنّ الدالة ()negative تقوم بعمل معالجة لعناصر مُعامل الشريحة الخاص بها. ها هو ناتج slice.go: $ go run slice.go 0 14 5 0 7 19 0 -14 -5 0 -7 -19 Before. Cap: 6, length: 6 After. Cap: 12, length: 7 0 -14 -5 0 -7 -19 -100 A new slice with 4 elements: 0 0 0 0 يُرجى ملاحظة أنه عند إنشاء شريحة جديدة وتخصيص مساحة ذاكرة لعدد معين من العناصر، فستعمل Go تلقائيًا على تهيئة جميع العناصر بقيمة الصفر من نوعها، والتي في هذه الحالة هي 0. الشرائح كمرجع للمصفوفات تُتيح لك Go الاشارة إلى مصفوفة موجودة بشريحة باستخدام الترميز [:]. في هذه الحالة، ستنعكس أي تغييرات تجريها على دالة شريحة إلى المصفوفة - وهذا موضّح في refArray.go. يرجى تذكُّر أن الترميز [:] لا يُنشئ نسخة من المصفوفة، بل فقط يُشير إليها. الجزء الأكثر إثارة للاهتمام في refArray.go هو: func main() { anArray := [5]int{-1, 2, -3, 4, -5} refAnArray := anArray[:] fmt.Println("Array:", anArray) printSlice(refAnArray) negative(refAnArray) fmt.Println("Array:", anArray) } ناتج refArray.go هو: $ go run refArray.go Array: [-1 2 -3 4 -5] -1 2 -3 4 -5 Array: [1 -2 3 -4 5] لذلك، تغيرت عناصر مجموعة anArray بسبب الإشارة إلى الشريحة. الملخص على الرغم من أن Go تدعم المصفوفات والشرائح، إلا أنه من الواضح إلى الآن أنك ستستخدم الشرائح على الأرجح لأنها أكثر تنوعًا وقوة من مصفوفات Go. لا يوجد سوى عدد قليل من الأحداث التي ستحتاج فيها إلى استخدام مصفوفة بدلاً من شريحة. الحدث الأكثر وضوحًا هو عندما تكون متأكدًا تمامًا من أنك ستحتاج إلى تخزين عدد محدد من العناصر. يمكنك العثور على كود Go الخاص بـ arrays.go و slice.go و refArray.go على GitHub. ترجمة -وبتصرف- للمقال An introduction to Go arrays and slices لصاحبه Mihalis Tsoukalos
  3. ستتعلم في هذا المقال ثلاث طرائق الأكثر شيوعًا لنسخ ملف عبر لغة البرمجة Go. هذا المقال جزء من سلسلة Go التي كتبها Mihalis Tsoukalos. اقرأ الجزء 1: إنشاء كلمات مرور عشوائية وآمنة في Go، والجزء 2: إنشاء خادم TCP متزامن في Go. بالرغم من وجود أكثر من ثلاث طرق لنسخ ملف في Go، يُقدم هذا المقال الطرق الثلاثة الأكثر شيوعًا: استخدام استدعاء دالة ()io.copy من مكتبة Go. قراءة ملف الإدخال مرة واحدة وكتابته إلى ملف آخر. نسخ الملف في قطع صغيرة باستخدام مخزن مؤقت. الطريقة الأولى: استخدام ()io.copy الإصدار الأول من هذه الطريقة يستخدم الدالة ()io.copy من مكتبة Go. يمكنك العثور على منطق هذه الطريقة من خلال الإطّلاع على كود الدالة ()copy، وهي كما يلي: func copy(src, dst string) (int64, error) { sourceFileStat, err := os.Stat(src) if err != nil { return 0, err } if !sourceFileStat.Mode().IsRegular() { return 0, fmt.Errorf("%s is not a regular file", src) } source, err := os.Open(src) if err != nil { return 0, err } defer source.Close() destination, err := os.Create(dst) if err != nil { return 0, err } defer destination.Close() nBytes, err := io.Copy(destination, source) return nBytes, err } بصرف النظر عن اختبار ما إذا كان الملف الذي سيتم نسخه موجودًا (عبر (os.Stat (src)، وهو ملف عادي (يمكن التأكد عبر sourceFileStat.Mode().IsRegular()‎)، حتى تتمكن من فتحه للقراءة، يتم تنفيذ كل العمل بواسطة الجملة التعريفية (io.copy(destination, Source السابقة. تُرجِع الدالة ()io.copy عدد البايتات المنسوخة ورسالة الخطأ الأولى التي حدثت أثناء عملية النسخ. في Go، إذا لم تكن هناك رسالة خطأ، فستكون قيمة متغير الخطأ صفر. يُمكنك معرفة المزيد عن ()io.copy بالإطّلاع على صفحة التوثيق الخاصة بـالـ io Package. سيؤدي تنفيذ cp1.go إلى إنشاء النوع التالي من النواتج: $ go run cp1.go Please provide two command line arguments! $ go run cp1.go fileCP.txt /tmp/fileCPCOPY Copied 3826 bytes! $ diff fileCP.txt /tmp/fileCPCOPY هذه التقنية بسيطة بقدر الإمكان ولكنها لا تعطي أي مرونة للمطور، وهذا ليس شيئًا سيئًا دائمًا. ومع ذلك، هناك أوقات يحتاج فيها المطور أو يريد أن يقرر كيف يريد قراءة الملف. الطريقة الثانية: استخدام ()ioutil.WriteFile و ()ioutil.ReadFile الطريقة الثانية لنسخ ملف هي استخدام الدوال ()ioutil.ReadFile و ()ioutil.WriteFile. تقرأ الدالة الأولى محتويات ملف بأكمله في شريحة بايت، بينما تقوم الدالة الثانية بكتابة محتويات شريحة بايت في ملف. يمكنك العثور على منطق هذه الطريقة في كود Go التالي: input, err := ioutil.ReadFile(sourceFile) if err != nil { fmt.Println(err) return } err = ioutil.WriteFile(destinationFile, input, 0644) if err != nil { fmt.Println("Error creating", destinationFile) fmt.Println(err) return } بصرف النظر عن كتلتي if، التي تُعد جزءًا من طريقة عمل Go، تستطيع أن ترى أنّ الأداء الوظيفي للبرنامج موجود في كلٍ من ()ioutil.ReadFile و ()ioutil.WriteFile. سيؤدي تنفيذ cp2.go إلى إنشاء نوع الناتج التالي: $ go run cp2.go Please provide two command line arguments! $ go run cp2.go fileCP.txt /tmp/copyFileCP $ diff fileCP.txt /tmp/copyFileCP يُرجى ملاحظة أنه على الرغم من أن هذه التقنية ستنسخ ملفًا، فقد لا تكون فعّالة عندما تريد نسخ ملفات ضخمة لأن شريحة البايت التي يتم إرجاعها بواسطة ()ioutil.ReadFile ستكون كبيرة هي الأخرى. الطريقة الثالثة: استخدام ()os.read و ()os.write الطريقة الثالثة لنسخ ملفات في Go، هي استخدام وسيلة cp3.go المُطوّرة في هذا القسم. تأخذ ثلاث معاملات: اسم ملف الإدخال. اسم ملف الإخراج. حجم المخزن المؤقت. يتواجد الجزء الأكثر أهمية من cp3.go في الحلقة for التالية، والذي يمكن العثور عليه في الدالة ()copy: buf := make([]byte, BUFFERSIZE) for { n, err := source.Read(buf) if err != nil && err != io.EOF { return err } if n == 0 { break } if _, err := destination.Write(buf[:n]); err != nil { return err } } تستخدم هذه التقنية الدالة ()os.read لقراءة أجزاء صغيرة من ملف الإدخال في المخزن المؤقت المُسمى buf. وتستخدم الدالة ()os.write لكتابة محتويات هذا المخزن المؤقت إلى ملف. تتوقف عملية النسخ عندما يكون هناك خطأ في القراءة أو عند الوصول إلى نهاية الملف (io.EOF). سيؤدي تنفيذ cp3.go إلى إنشاء نوع الناتج التالي: $ go run cp3.go usage: cp3 source destination BUFFERSIZE $ go run cp3.go fileCP.txt /tmp/buf10 10 Copying fileCP.txt to /tmp/buf10 $ go run cp3.go fileCP.txt /tmp/buf20 20 Copying fileCP.txt to /tmp/buf20 كما سترى، يؤثر حجم المخزن المؤقت بشكل كبير على أداء cp3.go. بعض من التقييم بهدف الموازنة سيحاول الجزء الأخير من هذ المقال موازنة البرامج الثلاثة بالإضافة إلى أداء cp3.go لمختلف أحجام المخزن المؤقت باستخدام الأداة المساعدة لسطر الأوامر (time (1. يُظهر الناتج التالي أداء cp1.go و cp2.go و cp3.go عند نسخ ملف بحجم 500 ميجابايت: $ ls -l INPUT -rw-r--r-- 1 mtsouk staff 512000000 Jun 5 09:39 INPUT $ time go run cp1.go INPUT /tmp/cp1 Copied 512000000 bytes! real 0m0.980s user 0m0.219s sys 0m0.719s $ time go run cp2.go INPUT /tmp/cp2 real 0m1.139s user 0m0.196s sys 0m0.654s $ time go run cp3.go INPUT /tmp/cp3 1000000 Copying INPUT to /tmp/cp3 real 0m1.025s user 0m0.195s sys 0m0.486s يُظهر الناتج أنّ أداء الأدوات المساعدة الثلاثة متشابه إلى حدٍ ما، مما يعني أن دوال مكتبة Go القياسية ذكية ومُحسَّنة تمامًا. الآن، دعنا نختبر كيف يؤثر حجم المخزن المؤقت على أداء cp3.go. سيؤدي تنفيذ cp3.go بحجم المخزن المؤقت 10 و 20 و 1000 بايت لنسخ ملف 500 ميجابايت على جهاز سريع إلى حد كبير لاستخراج النتائج التالية: $ ls -l INPUT -rw-r--r-- 1 mtsouk staff 512000000 Jun 5 09:39 INPUT $ time go run cp3.go INPUT /tmp/buf10 10 Copying INPUT to /tmp/buf10 real 6m39.721s user 1m18.457s sys 5m19.186s $ time go run cp3.go INPUT /tmp/buf20 20 Copying INPUT to /tmp/buf20 real 3m20.819s user 0m39.444s sys 2m40.380s $ time go run cp3.go INPUT /tmp/buf1000 1000 Copying INPUT to /tmp/buf1000 real 0m4.916s user 0m1.001s sys 0m3.986s يُظهر الناتج الذي تم إنشاؤه أنه كلما زاد حجم المخزن المؤقت، كلما كان أداء cp3.go أسرع، وهو أمر مُتوَقع إلى حدٍ ما. علاوةً على ذلك، يُعد استخدام أحجام المخازن المؤقتة أصغر من 20 بايت لنسخ الملفات الكبيرة عملية بطيئة للغاية ويجب تجنُّبها. يمكنك العثور على كود Go الخاص بـ cp1.go و cp2.go و cp3.go على Github. ترجمة وبتصرّف للمقال 3 ways to copy files in Go، لصاحبه Mihalis Tsoukalos.
  4. سنعمل في هذا المقال على تطوير خادم TCP متزامن يقوم بإنشاء أرقام عشوائية باستخدام حوالي 65 سطرًا من كود Go، إذ سأشرح كيفية تطوير خادم TCP متزامن، بلغة البرمجة Go، والتي تقوم بإرجاع أرقام عشوائية. إن لم تقرأ المقال السابق حول إنشاء كلمات مرور عشوائية وآمنة في Go، فننصحك بالرجوع إليه وقراءته أولًا. تعمل خوادم TCP و UDP بخدمة عملاء الشبكة في كل مكان عبر شبكات TCP / IP. لكل اتصال وارد من عميل TCP، سيقوم خادم TCP ببدء تشغيل goroutine جديد لمعالجة هذا الطلب. تستطيع إيجاد هذا المشروع concTCP.go على GitHub. التعامل مع اتصالات TCP يمكنك العثور على منطق البرنامج في دالة ()handleConnection بلغة Go، والذي يتم تنفيذه على النحو التالي: func handleConnection(c net.Conn) { fmt.Printf("Serving %s\n", c.RemoteAddr().String()) for { netData, err := bufio.NewReader(c).ReadString('\n') if err != nil { fmt.Println(err) return } temp := strings.TrimSpace(string(netData)) if temp == "STOP" { break } result := strconv.Itoa(random()) + "\n" c.Write([]byte(string(result))) } c.Close() } إذا أرسل عميل TCP سلسلة التعليمات "STOP"، فسيتم إنهاء برنامج Go أي goroutine الذي يخدم عميل TCP محدد؛ وإلا، سيرسل خادم TCP رقمًا عشوائيًا إلى عميل TCP. تضمن الحلقة for أن عميل TCP سيتم خدمته طالما يُتَطلب ذلك. تقرأ الحلقة for الموجودة في كود Go البيانات من عميل TCP سطرًا بسطر باستخدام ('bufio.NewReader(c).ReadString('\n وتُعيد إرسال البيانات باستخدام (((c.Write([]byte(string(result. التزامن تنفيذ دالة ()main، يُعطي أمرًا لخادم TCP لبدء تشغيل برنامج goroutine جديد في كل مرة يتعين عليه خدمة عميل TCP: func main() { arguments := os.Args if len(arguments) == 1 { fmt.Println("Please provide a port number!") return } PORT := ":" + arguments[1] l, err := net.Listen("tcp4", PORT) if err != nil { fmt.Println(err) return } defer l.Close() rand.Seed(time.Now().Unix()) for { c, err := l.Accept() if err != nil { fmt.Println(err) return } go handleConnection(c) } } أولاً، تتأكد ()main من أن البرنامج يحتوي على وسيطة سطر أوامر واحدة على الأقل. لاحظ أن الكود الموجود لا يتحقق مما إذا كانت وسيطة سطر الأوامر المحددة هي رقم مَنفذ TCP صالح أم لا. ومع ذلك، إذا لم تكن القيمة المحددة رقم منفذ TCP صالحًا، فسوف يفشل استدعاء ()net.Listen مع ظهور رسالة خطأ مشابهة لما يلي: $ go run concTCP.go 12a listen tcp4: lookup tcp4/12a: nodename nor servname provided, or not known $ go run concTCP.go -10 listen tcp4: address -10: invalid port يتم استخدام استدعاء ()net.Listen لإخبار برنامج Go بقبول اتصالات الشبكة وبالتالي كخادم. قيمة الإرجاع ()net.Listen هي من النوع net.Conn، والتي تنفذ واجهات io.Reader و io.Writer. تقوم الدالة ()main أيضًا باستدعاء الدالة ()rand.seed لتهيئة مُنشئ الأرقام العشوائية. أخيرًا، تُتيح حلقة for للبرنامج الحفاظ على قبول عملاء TCP الجدد باستخدام ()accept والتي سيتم معالجتها بواسطة نسخ الدالة ()handleConnection، والتي يتم تنفيذها على شكل goroutines. أول معامل للدالة ()net.Listen يُحدد المعامل الأول من الدالة ()net.Listen نوع الشبكة التي سيتم استخدامها، بينما يُحدد المعامل الثاني عنوان الخادم بالإضافة إلى رقم المَنفذ الذي سيستمع إليه الخادم. القيم الصالحة للمُعامل الأول هي: tcp, tcp4 (IPv4-only), tcp6 (IPv6-only), udp, udp4 (IPv4- only), udp6 (IPv6-only), ip, ip4 (IPv4-only), ip6 (IPv6-only), Unix (Unix sockets), Unixgram, Unixpacket فعالية خادم TCP المتزامن يتطلب concTCP.go وسيطة سطر أوامر واحدة، وهي رقم المَنفذ الذي سيستمع إليه. سيكون الناتج الذي ستحصل عليه من concTCP.go عند خدمة عملاء TCP مشابهًا لما يلي: $ go run concTCP.go 8001 Serving 127.0.0.1:62554 Serving 127.0.0.1:62556 يمكن لناتج (1)netStat التحقق من أن concTCP.go يخدم العديد من عملاء TCP أثناء الاستماع لمزيد من الاتصالات: $ netstat -anp TCP | grep 8001 tcp4 0 0 127.0.0.1.8001 127.0.0.1.62556 ESTABLISHED tcp4 0 0 127.0.0.1.62556 127.0.0.1.8001 ESTABLISHED tcp4 0 0 127.0.0.1.8001 127.0.0.1.62554 ESTABLISHED tcp4 0 0 127.0.0.1.62554 127.0.0.1.8001 ESTABLISHED tcp4 0 0 *.8001 *.* LISTEN يعلمنا السطر الأخير من ناتج الأمر السابق أن هناك عملية تستمع إلى المَنفذ 8001، مما يعني أنه لا يزال بإمكانك الاتصال بمنفذ TCP رقم 8001. يتحقق أول سطرين من وجود اتصال شبكة TCP ثابت يستخدم أرقام المنافذ 8001 و 62556. وبالمثل، يتحقق السطران الثالث والرابع من وجود اتصال TCP آخر يستخدم أرقام المنافذ 8001 و 62554. تُظهر هذه الصورة ناتج concTCP.go عند خدمة العديد من عملاء TCP: بشكل مشابه، تُظهر الصورة التالية الناتج من عميلين من TCP يتم تنفيذهما باستخدام (1)nc: يُمكنك ايجاد معلومات أكثر عن (1)nc، والتي تُدعى أيضًا (1)netcat على ويكيبيديا. الملخص لقد تعلمت للتو كيفية تطوير خادم TCP متزامن يقوم بإنشاء أرقام عشوائية باستخدام حوالي 65 سطرًا من كود Go، وهو أمر مثير للإعجاب جدًا! إذا كنت تريد أن يقوم خادم TCP بمهمة مختلفة، فقط قم بتغيير تنفيذ الدالة ()handleConnection. ترجمة وبتصرّف للمقال Build a concurrent TCP server in Go، لصاحبه Mihalis Tsoukalos.
  5. يعد مولد الأرقام العشوائية لـ Go طريقة رائعة لإنشاء كلمات مرور يصعب تخمينها. يمكنك استخدام مولد الأرقام العشوائية الذي توفره لغة البرمجة Go لإنشاء كلمات مرور يصعب تخمينها تتكون من رموز ASCII. على الرغم من أن الكود المقدَّم في هذا المقال سهل القراءة، إلا أنّه يُفضَّل أن تكون على معرفةٍ سابقة بأساسيات Go لفهمها. إذا كنت حديث العهد بلغات البرمجة، فاختر مدخل إلى لغة البرمجة Go لمعرفة المزيد حول Go، ثم عد إلى هنا. قبل التعمُّق في الأدوات المساعدة والكود الخاص بـ Go، ألقِ نظرة على هذه المجموعة الفرعية من جدول ASCII كما هو موجود في ناتج الأمر man ascii: 30 40 50 60 70 80 90 100 110 120 --------------------------------- 0: ( 2 < F P Z d n x 1: ) 3 = G Q [ e o y 2: * 4 > H R \ f p z 3: ! + 5 ? I S ] g q { 4: " , 6 @ J T ^ h r | 5: # - 7 A K U _ i s } 6: $ . 8 B L V ` j t ~ 7: % / 9 C M W a k u DEL 8: & 0 : D N X b l v 9: ' 1 ; E O Y c m w القيم العشرية لرموز ASCII تتراوح من 33 إلى 126؛ لا توجد قيم ASCII أخرى مناسبة لتتواجد ضمن كلمات المرور. لذلك، سوف تنتج الأدوات المساعدة المقدَّمة في هذا المقال أحرف ASCII في هذا النطاق. خلق أعداد صحيحة عشوائية الأداة المساعدة الأولى تُدعى random.go، وتقوم بإنشاء عدد محدد من الأعداد الصحيحة العشوائية ضمن نطاق معين. الجزء الأكثر أهمية في random.go هو هذه الدالة: func random(min, max int) int { return rand.Intn(max-min) + min } تقوم هذه الدالّة بإنشاء أعداد صحيحة عشوائية تنتمي إلى نطاق معين باستخدام ()rand.intn. لاحظ أنّ rand.intn()‎ تقوم بإرجاع رقم عشوائي غير سالب ينتمي إلى المجال [0,n)، إذ n هو العدد المُمرَّر إلى الدالة. ستخرب الدالة إذا كان مُعاملها عددًا سالبًا وستكون رسالة الخطأ كما يلي: panic: invalid argument to Intn يُمكنك إيجاد توثيق المجموعة math/rand في هذا الرابط: math/rand Documentation. تقبل الدالة random.go ثلاثًا من عوامل سطر الأوامر (Command Line Parameters): الحد الأدنى لقيمة الأعداد الصحيحة المراد توليدها. والقيمة القصوى. وعدد الأعداد الصحيحة التي سيتم توليدها. تجميع وتنفيذ random.go سيخلق هذا النوع من الناتج: $ go build random.go $ ./random Usage: ./random MIX MAX TOTAL $ ./random 1 3 10 2 2 1 2 2 1 1 2 2 1 إذا كنت ترغب في إنشاء أرقام عشوائية أكثر أمانًا في Go، فاستخدم حزمة crypto / rand من مكتبة Go. إنشاء كلمات مرور عشوائية الأداة المساعدة الثانية randomPass.go، تنشئ كلمات مرور عشوائية. يستخدم randomPass.go الدالة ()random لإنشاء أرقام عشوائية سيتم تحويلها إلى رموز ASCII باستخدام كود Go التالي: for { myRand := random(MIN, MAX) newChar := string(startChar[0] + byte(myRand)) fmt.Print(newChar) if i == LENGTH { break } i++ } قيمة MIN هي 0 وقيمة MAX هي 94، في حين أن قيمة startChar هي !، وهو أول حرف قابل للطباعة في جدول ASCII (برمز ASCII العشري وهو 33). لذلك، توجد جميع أحرف ASCII التي سيتم إنشاؤها بعد ! وقبل الحرف ~، الذي يحتوي على رمز ASCII العشري لـلرقم 126. لذلك، كل رقم عشوائي يتم إنشاؤه أكبر من MIN، وأصغر من MAX، ويتم تحويله إلى رمز ASCII. تستمر العملية حتى تصبح كلمة المرور التي تم إنشاؤها لها بالطول المطلوب. تقبل randomPass.go معامل سطر أوامر واحد (اختياري) يُحدد طول كلمة المرور التي تم إنشاؤها. القيمة الافتراضية هي ثمانية، وهو طول كلمة مرور شائع جدًا. سيؤدي تنفيذ randomPass.go إلى الناتج التالي: $ go run randomPass.go 1 Z $ go run randomPass.go 10 #Cw^a#IwkT $ go run randomPass.go Using default values! [PP8@'Ci تفصيل أخير: لا تنس استعمال ()rand.seed مع قيمة أولية لتهيئة مولد الأرقام العشوائية. إذا استخدمت نفس القيمة الأولية في كل وقت، فسيقوم مُولِّد الأرقام العشوائية بإنشاء نفس تسلسل الأعداد الصحيحة العشوائية. تستطيع إيجاد كلًا من random.go و randomPass.go على GitHub. وتستطيع أيضًا تنفيذ هذه الدوال على play.golang.org ترجمة -وبتصرف- للمقال Creating random, secure passwords in Go لصاحبه Mihalis Tsoukalos.