المحتوى عن 'golang'.



مزيد من الخيارات

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المُحتوى


التصنيفات

  • التخطيط وسير العمل
  • التمويل
  • فريق العمل
  • دراسة حالات
  • نصائح وإرشادات
  • التعامل مع العملاء
  • التعهيد الخارجي
  • التجارة الإلكترونية
  • الإدارة والقيادة
  • مقالات ريادة أعمال عامة

التصنيفات

  • PHP
    • Laravel
    • ووردبريس
  • جافاسكريبت
    • Node.js
    • jQuery
    • AngularJS
    • Cordova
  • HTML
    • HTML5
  • CSS
  • SQL
  • سي شارب #C
    • منصة Xamarin
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • Sass
    • إطار عمل Bootstrap
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • برمجة أندرويد
  • لغة Swift
  • لغة R
  • لغة TypeScript
  • ASP.NET
    • ASP.NET Core
  • سير العمل
    • Git
  • صناعة الألعاب
    • Unity3D
  • مقالات برمجة عامة

التصنيفات

  • تجربة المستخدم
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
    • كوريل درو
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • نصائح وإرشادات
  • مقالات تصميم عامة

التصنيفات

  • خواديم
    • الويب HTTP
    • قواعد البيانات
    • البريد الإلكتروني
    • DNS
    • Samba
  • الحوسبة السّحابية
    • Docker
  • إدارة الإعدادات والنّشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • مقالات DevOps عامة

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • التسويق بالرسائل النصية القصيرة
  • استسراع النمو
  • المبيعات
  • تجارب ونصائح

التصنيفات

  • إدارة مالية
  • الإنتاجية
  • تجارب
  • مشاريع جانبية
  • التعامل مع العملاء
  • الحفاظ على الصحة
  • التسويق الذاتي
  • مقالات عمل حر عامة

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
  • أندرويد
  • iOS
  • macOS
  • ويندوز

التصنيفات

  • شهادات سيسكو
    • CCNA
  • شهادات مايكروسوفت
  • شهادات Amazon Web Services
  • شهادات ريدهات
    • RHCSA
  • شهادات CompTIA
  • مقالات عامة

أسئلة وأجوبة

  • الأقسام
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة البرمجة
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات
    • أسئلة الشهادات المتخصصة

التصنيفات

  • ريادة الأعمال
  • العمل الحر
  • التسويق والمبيعات
  • البرمجة
  • التصميم
  • DevOps

تمّ العثور على 6 نتائج

  1. تزداد شعبية Go، وهي لغة برمجة حديثة تطوّرها شركة Google، تزداد كثيرا في التطبيقات والشركات؛ كما توفّر مجموعة متناسقة من المكتبات البرمجية. يشرح هذا الدرس خطوات تثبيت الإصدار 1.8 (الإصدار المستقر الأحدث حتى الآن) على توزيعة لينكس أوبونتو 16.04. سننفّذ في الخطوة الأخيرة من هذا الدرس تطبيق “أهلا بالعالم” صغيرا للتأكد من تثبيت مصرّف اللغة Compiler وعمله. المتطلّبات يفترض هذا الدرس توفّر نظام أوبونتو 16.04 معدًّا للعمل مع مستخدم إداري غير المستخدم الجذر بالطريقة التي يشرحها الإعداد الابتدائي لخادوم أوبونتو. الخطوة الأولى: تثبيت Go نبدأ بتثبيت Go على الخادوم. اتّصل - إن دعت الحاجة لذلك - بالخادوم عن طريق SSH: ssh sammy@your_server_ip اذهب إلى صفحة التنزيلات على الموقع الرسمي لـGo واعثُر على رابط الملف المضغوط لآخر إصدار مستقر، مع قيمة تجزئة SHA256 الخاصة به. تأكد من أنك في المجلّد الشخصي للمستخدم ثم نزّل الإصدار انطلاقا من الرابط الذي تحصّلت عليه في الفقرة الماضية: cd ~ curl -O https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz استخدم الأمر sha256sum للتحقّق من الملف المضغوط: sha256sum go1.8.3.linux-amd64.tar.gz مثال على المُخرجات: 1862f4c3d3907e59b04a757cfda0ea7aa9ef39274af99a784f5be843c80c6772 go1.8.3.linux-amd64.tar.gz ستحصُل على قيمة تجزئة Hash مثل تلك الموجودة في المُخرجات السابقة. تأكد من أنها توافق قيمة التجزئة الخاصة بالملف التي تحصّلت عليها من صفحة التنزيلات. سنستخدم الآن الأمر tar لفك ضغط الملف. يطلُب الخيار x استخراج محتوى الملف المضغوط، يُظهر الخيار v مخرجات مفصَّلة ويحدّد الخيار f أننا سنمرّر للأمر tar اسم الملف المضغوط: tar xvf go1.6.linux-amd64.tar.gz ستحصُل الآن على مجلّد باسم go في المجلّد الشخصي للمستخدم. نفّذ الأمرين التاليين لتعديل ملكية المجلّد go ثم نقله إلى المسار usr/local/ : sudo chown -R root:root ./go sudo mv go /usr/local ملحوظة: المسار usr/local/go/ هو المسار المنصوح به رسميا لتثبيت Go إلا أن بعض الحالات قد تتطلّب تثبيته على مسار مختلف. الخطوة الثانية: ضبط مسارات Go سنضبُط في هذه الخطوة المسارات الخاصّة بـGo في بيئة النظام. نفتح الملف profile./~ لتحريره: sudo nano ~/.profile نضيف السطرين التاليّين في نهاية الملف لضبط قيمة المتغيّر GOPATH، الذي يحدّد المسار الذي يجب على المصرّف البحثُ فيه عن الملفات المكتوبة بـGo، ولإضافة هذا المسار إلى متغيّر النظام PATH: export GOPATH=$HOME/work export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin أضف الأسطر أدناه إلى الملف بدلا من الأسطر السابقة إن اخترت مسارا غير الذي اخترناه لتثبيت Go. يفترض المثال أن Go مثبَّت في المجلّد الشخصي للمستخدم: export GOROOT=$HOME/go export GOPATH=$HOME/work export PATH=$PATH:$GOROOT/bin:$GOPATH/bin نغلق الملف بعد التحرير ونعتمد التغيير بتنفيذ الأمر source: source ~/.profile الخطوة الثالثة: اختبار التثبيت نتأكّد بعد أن ثبّتنا Go وضبطنا مساراته من عمله. أنشئ مجلّدا جديدا لحفظ ملفات Go. مسار هذا الملف هو نفس المسار الذي حدّدناه في المتغيّر GOPATHضمن الخطوة السابقة: mkdir $HOME/work أنشئ مجلّدات مشاريع Go ضمن هذا المجلد كما في المثال التالي. يمكنك إبدال user في المسار أدناه باسم المستخدم الخاصّ بك على GitHub إن كنت تخطّط لاستخدام Git لإيداع شفرتك البرمجية على GitHub. إن لم تكن تخطّط لذلك فيمكن اختيار تسميات أخرى مثل my_project. mkdir -p work/src/github.com/user/hello ننشئ ملفّ Go بسيطا للتجربة، ونسميه hello: nano ~/work/src/github.com/user/hello/hello.go ألصق شفرة Go التالية ضمن محرّر النصوص. تستخدم هذه الشفرة حزمة main في Go، تستورد مكتبة fmt لدوالّ الإدخال والإخراج وتضبُط دالة جديدة لطباعة الجملة hello, world. package main import "fmt" func main() { fmt.Printf("hello, world\n") } يطبع البرنامج السابق عند تنفيذه بنجاح العبارة hello, world، وهو ما يدلّ على نجاح تصريف Compiling شفرة Go. احفظ الملف ثم أغلقه؛ ثم صرّفه باستدعاء الأمر go install: go install github.com/user/hello يمكننا الآن تشغيل البرنامج بتنفيذ الأمر hello: hello إن تمّ كل شيء على ما يُرام فستُطبَع العبارة hello, world. يمكنك معرفة أين يوجد الملف التنفيذي للبرنامج (ناتج التصريف) بتمرير اسمه إلى الأمر which: which hello مثال على المُخرجات: /home/user/work/bin/hello خاتمة يصبح لديك بعد تنزيل حزمة Go وتثبيتها وضبط مساراتها نظام جاهز لاستخدامه في التطوير بلغة Go. يمكنك الآن البدء بتعلم كتابة البرامج بهذه اللغة، راجع قسم البرمجة بلغة Go للمزيد. ترجمة - بتصرّف - للمقال How to Install Go 1.6 on Ubuntu 16.04 لصاحبه Brennen Bearnes.
  2. بدأ تطوير لغة البرمجة Go بتجربة من مهندسين يعملون في Google لتلافي بعض التعقيدات الموجودة في لغات برمجة أخرى مع الاستفادة من نقاط قوّتها. تُطوَّر لغة Go باستمرار بمشاركة مجتمع مفتوح المصدر يزداد باضطّراد. تهدف لغة البرمجة Go إلى أن تكون سهلة، إلا أن اصطلاحات كتابة الشفرة البرمجية في Go قد تكون صعبة الاستيعاب. سأريكم في هذا الدرس كيف أبدأ جميع مشاريعي البرمجية عندما أستخدم Go، وكيفية استخدام التعابير التي توفّرها هذه اللغة. سننشئ خدمة سند خلفي Backend لتطبيق وِب. إعداد بيئة العمل الخطوة الأولى هي - بالطبع - تثبيتُ Go. يمكن تثبيت Go من المستودعات الرسمية على توزيعات لينكس؛ مثلا بالنسبة لأوبونتو: sudo apt install golang-go إصدارات Go الموجودة في المستودعات الرسمية تكون في العادة أقدم قليلا من تلك الموجودة على الموقع الرسمي، إلا أنها تؤدي الغرض؛ علاوة على سهولة التثبيت. يمكنك تثبيت إصدارات أحدث على أوبونتو (هنا) وCentos (هنا). بالنسبة لمستخدمي نظام Mac OS فيمكنهم تثبيت اللغة عن طريق Homebrew: brew install go يحوي الموقع الرسمي كذلك الملفات التنفيذية لتثبيت اللغة على أغلب أنظمة التشغيل، بما في ذلك ويندوز. تأكّد من تثبيت Go بتنفيذ الأمر التالي: go version مثال لنتيجة اﻷمر أعلاه (على توزيعة أوبونتو): go version go1.6.2 linux/amd64 – روابط للتثبيت على وندوز وإعداد المسارات – توجد الكثير من محرّرات النصوص والإضافات المتاحة لكتابة شفرات Go. أفضّل شخصيّا محرّر الشفرات Sublime Text وإضافة GoSublime؛ إلا أن طريقة كتابة Go تتيح استخدام محرّرات نصوص عاديّة بسهولة خصوصا للمشاريع الصغيرة. أعمل مع محترفين يقضون كامل اليوم في البرمجة بلغة Go باستخدام محرّر النصوص Vim، دون أي إضافة لإبراز صيغة الشفرات البرمجية Syntax highlighting. بالتأكيد لن تحتاج لأكثر من محرّر نصوص بسيط للبدء في تعلّم Go. مشروع جديد إن لم تكن أنشأت مجلّدا للعمل أثناء تثبيت Go وإعداده فالوقت مناسب لذلك. تتوقّع أدوات Go أن توجد جميع الشفرات البرمجية على المسار GOPATH/src$، وبالتالي سيكون عملنا دائما في هذا المجلّد. يمكن لمجموعة أدوات Go كذلك أن تتخاطب مع مشاريع مُضيَّفة على مواقع مثل GitHub وBitbucket إن أُعدّت لذلك. سننشئ لأغراض هذا الدرس مستودعا جديدا فارغا على GitHub ولنسمّه “hello” (أو أي اسم يناسبك). ننشئ مجلّدا ضمن مجلّد GOPATH لاستقبال ملفات المستودع (أبدل your-username باسم المستخدم الخاصّ بك على GitHub): mkdir -p $GOPATH/src/github.com/your-username cd $GOPATH/src/github.com/your-username ننسخ المستودع ضمن المجلّد الذي أنشأناه أعلاه: git clone git@github.com:your-username/hello cd hello سننشئ الآن ملفا باسم main.go ليحوي برنامجا قصيرا بلغة Go: package main func main() { println("hello!") } نفّذ الأمر go build لتصريف جميع محتويات المجلّد الحالي. سينتُج ملف تنفيذي بنفس الاسم؛ يمكنك بعدها طلب تشغيله بذكر اسمه على النحو التالي: go build ./hello النتيجة: hello! ما زلت رغم سنوات من التطوير بلغة Go أبدأ مشاريعي بنفس الطريقة: مستودع Git فارغ، ملف main.go وبضعة أوامر. يصبح أي تطبيق يتبع الطرق المتعارف عليها لتنظيم شفرة Go قابلا للتثبيت بسهولة بالأمر go get. إن أودعت على سبيل المثال الملف أعلاه ودفعته إلى مستودع Git فإن أي شخص لديه بيئة عمل Go يمكنه تنفيذ الخطوتين التاليتين لتشغيل البرنامج: go get github.com/your-username/hello $GOPATH/bin/hello إنشاء خادوم وب فلنجعل برنامجنا البسيط السابق خادوم وب: package main import "net/http" func main() { http.HandleFunc("/", hello) http.ListenAndServe(":8080", nil) } func hello(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hello!")) } هناك بضعة سطور تحتاج للشرح. نحتاج أولا لاستيراد الحزمة net/httpمن المكتبة المعيارية لـGo: import "net/http" ثم نثبّت دالة معالجة Handler function في المسار الجذر لخادوم الوِب. تتعامل http.HandleFunc مع الموجّه المبدئي لطلبات Http في Go، وهو ServeMux. http.HandleFunc("/", hello) الدالة hello هي من النوع http.HandlerFunc الذي يسمح باستخدام دوال عاديّة على أنها دوال معالجة لطلبات HTTP. للدوال من النوع http.HandlerFunc توقيع Signature خاص (توقيع الدالة هو المعطيات المُمرَّرة لها وأنواع البيانات التي تُرجعها هذه الدالة) ويمكن تمريرها في معطى إلى الدالة HandleFunc التي تسجّل الدالة المُمرَّرة في المُعطى لدى الموجِّه ServeMux، وبالتالي يُنشئ خادوم الوِب، في كلّ مرة يصله فيها طلب جديد يطابق المسار الجذر، يُنشئ نسخة جديدة من الدالة hello. تستقبل الدالة hello متغيّرا من النوع http.ResponseWriter الذي تستخدمه الدالة المُعالِجة لإنشاء إجابة HTTP وبالتالي إنشاء ردّ على طلب العميل عن طريق التابع Write الذي يوفّره النوع http.ResponseWriter. بما أن التابع http.ResponseWriter.Write يأخذ معطى عامًّا من النوع []byte أو byte-slice، فنحوّل السلسة النصيّة hello إلى النوع المناسب: func hello(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hello!")) } في الأخير نشغّل خادوم وب على المنفذ 8080 عبر الدالة http.ListenAndServe التي تستقبل معطيَين، الأول هو المنفَذ Port والثاني دالة معالجة. إذا كانت قيمة المعطى الثاني هي nil فهذا يعني أننا نريد استخدام الموجّه المبدئي DefaultServeMux. هذا الاستدعاء متزامن Synchronous، أو معترِض Blocking، يبقي البرنامج قيد التشغيل إلى أن يُقطَع الاستدعاء. صرّف وشغّل البرنامج بنفس الطريقة السابقة: go build ./hello افتح سطر أوامر - طرفيّة - آخر وأرسل طلب HTTP إلى المنفذ 8080: curl http://localhost:8080 النتيجة: hello! الأمر بسيط. ليست هناك حاجة لتثبيت إطار عمل خارجي، أو تنزيل اعتماديات Dependencies أو إنشاء هياكل مشاريع. الملف التنفيذي نفسه هو شفرة أصيلة Native code بدون اعتمادات تشغيلية. علاوة على ذلك، المكتبة المعيارية لخادوم الوِب موجهة لبيئة الإنتاج مع دفاعات ضدّ الهجمات الإلكترونية الشائعة. يمكن لهذه الشفرة الإجابة على الطلبات عبر الشبكة مباشرة ودون وسائط. إضافة مسارات جديدة يمكننا فعل أمور أكثر أهمية من مجرّد قول مرحبا (hello). فليكن المُدخَل اسم مدينة نستخدمه لاستدعاء واجهة تطبيقات برمجيّة API لأحوال الطقس ونعيد توجيه الإجابة - درجة الحرارة - في الرد على الطلب. توفّر خدمة OpenWeatherMap واجهة تطبيقات برمجيّة مجانيّة وسهلة الاستخدام للحصول على توقّعات مناخية. سجّل في الموقع للحصول على مفتاح API. يمكن الاستعلام من OpenWeatherMap حسب المدن. تُرجع واجهة التطبيقات البرمجية إجابة على النحو التالي (عدّلنا قليلا على النتيجة): { "name": "Tokyo", "coord": { "lon": 139.69, "lat": 35.69 }, "weather": [ { "id": 803, "main": "Clouds", "description": "broken clouds", "icon": "04n" } ], "main": { "temp": 296.69, "pressure": 1014, "humidity": 83, "temp_min": 295.37, "temp_max": 298.15 } } المتغيّرات في Go ذات أنواع ثابتة Statical type، بمعنى أنه ينبغي التصريح بنوع البيانات التي تخزّنها المتغيّرات قبل استخدامها. لذا سيتوجّب علينا إنشاء بنية بيانات لمطابقة صيغة رد الواجهة البرمجية. لا نحتاج لحفظ جميبع المعلومات، بل يكفي أن نحتفظ بالبيانات التي نهتم بشأنها. سنكتفي الآن باسم المدينة ودرجة الحرارة المتوقّعة التي تأتي بوحدة الكيلفن Kelvin. سنعرّف بنية لتمثيل البيانات التي نحتاجها من خدمة التوقعات المناخية. type weatherData struct { Name string `json:"name"` Main struct { Kelvin float64 `json:"temp"` } `json:"main"` } تعرّف الكلمة المفتاحية type بنية بيانات جديدة نسمّيها weatherData ونصرّح بكونها من النوع struct. يحوي كلّ حقل في المتغيّرات من نوع struct اسما (مثلا Name أو Main)، نوع بيانات (string أو struct آخر مجهول الاسم) وما يُعرَف بالوسم Tag. تشبه الوسوم في Go البيانات الوصفية Metadata، وتمكّننا من استخدام الحزمة encoding/json لإعادة صفّ الإجابة التي تقدّمها خدمة OpenWeatherMap وحفظها في بنية البيانات التي أعددناها. يتطلّب الأمر كتابة شفرة برمجية أكثر ممّا عليه الحال في لغات برمجيّة ذات أنواع ديناميكية للبيانات (بمعنى أنه يمكن استخدام متغيّر فور احتياجنا له دون الحاجة للتصريح بنوع البيانات) مثل روبي وبايثون، إلا أنه يمنحنا خاصيّة الأمان في نوع البيانات. عرّفنا بنية البيانات، نحتاج الآن لطريقة تمكّننا من ملْء هذه البنية بالبيانات القادمة من واجهة التطبيقات البرمجية؛ سنكتُب دالة لهذا الغرض. func query(city string) (weatherData, error) { resp, err := http.Get("http://api.openweathermap.org/data/2.5/weather?APPID=YOUR_API_KEY&q=" + city) if err != nil { return weatherData{}, err } defer resp.Body.Close() var d weatherData if err := json.NewDecoder(resp.Body).Decode(&d); err != nil { return weatherData{}, err } return d, nil } تأخذ الدالة سلسلة محارف تمثّل المدينة وتُرجِع متغيّرا من بنية بيانات weatherData وخطأ. هذه هي الطريقة الأساسية للتعامل مع الأخطاء في Go. تغلّف الدوال سلوكا معيَّنا، ويمكن أن يخفق هذا السلوك. بالنسبة لمثالنا، يمكن أن يخفق طلب GET الذي نرسله لـOpenWeatherMap لأسباب عدّة، وقد تكون البيانات المُرجَعة غير تلك التي ننتظرها. نُرجِع في كلتا الحالتين خطأ غير فارغ Non-nil للعميل الذي يُنتظَر منه أن يتعامل مع هذا الخطأ بما يتناسب مع السياق الذي أرسل فيه الطلب. إن نجح الطلب http.Get نؤجّل طلبا لغلق متن الإجابة لننفّذه بعد الخروج من نطاق Scope الدالة (أي بعد الرجوع من دالة طلب HTTP)، وهي طريقة أنيقة لإدارة الموارد. في أثناء ذلك نحجز بنية weatherData ونستخدم json.Decoder لقراءة بيانات الإجابة وإدخالها مباشرة في بنيتنا. عندما تنجح إعادة صياغة بيانات الإجابة نعيد المتغيّر weatherData إلى المُستدعي مع خطأ فارغ للدلالة على نجاح العملية. ننتقل الآن إلى ربط تلك الدالة بالدالة المعالجة للطلب: http.HandleFunc("/weather/", func(w http.ResponseWriter, r *http.Request) { city := strings.SplitN(r.URL.Path, "/", 3)[2] data, err := query(city) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") json.NewEncoder(w).Encode(data) }) نعرّف دالة معالجة على السطر In-line بدلا من تعريفها منفصلة. نستخدم الدالة strings.SplitN لأخذ كل ما يوجد بعد /weather/ في المسار والتعامل معه على أنه اسم مدينة. ننفّذ الطلب وإن صادفتنا أخطاء نعلم العميل بها باستخدام الدالة المساعدة http.Error، ونوقف تنفيذ الدالة للدلالة على اكتمال طلب HTTP. إن لم يوجد خطأ نخبر العميل بأننا بصدد إرسال بيانات JSON إليه ونستخدم الدالة json.NewEncode لترميز محتوى weatherData بصيغة JSON مباشرة. الشفرة لحدّ الساعة أنيقة، تعتمد أسلوبا إجرائيا Procedural ويسهل فهمها. لا مجال للخطأ في تفسيرها ولا يمكنها تجاوز الأخطاء الشائعة. إن نقلنا الدالة المعالجة لـ "hello, world" إلى المسار hello/ واستوردنا الحزم المطلوبة فسنحصُل على البرنامج المُكتمل التالي: package main import ( "encoding/json" "net/http" "strings" ) func main() { http.HandleFunc("/hello", hello) http.HandleFunc("/weather/", func(w http.ResponseWriter, r *http.Request) { city := strings.SplitN(r.URL.Path, "/", 3)[2] data, err := query(city) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") json.NewEncoder(w).Encode(data) }) http.ListenAndServe(":8080", nil) } func hello(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hello!")) } func query(city string) (weatherData, error) { resp, err := http.Get("http://api.openweathermap.org/data/2.5/weather?APPID=YOUR_API_KEY&q=" + city) if err != nil { return weatherData{}, err } defer resp.Body.Close() var d weatherData if err := json.NewDecoder(resp.Body).Decode(&d); err != nil { return weatherData{}, err } return d, nil } type weatherData struct { Name string `json:"name"` Main struct { Kelvin float64 `json:"temp"` } `json:"main"` } نصرّف البرنامج وننفّذه بنفس الطريقة التي شرحناها أعلاه: go build ./hello نفتح طرفيّة أخرى ونطلب المسار http://localhost:8080/weather/tokyo (الحرارة بمقياس كلفن): curl http://localhost:8080/weather/tokyo النتيجة: {"name":"Tokyo","main":{"temp":295.9}} الاستعلام من واجهات برمجية عدّة ربما من الممكن الحصول على درجات حرارة أكثر دقّة إن استعلمنا من خدمات طقس عدّة وحسبنا المتوسّط بينها. تتطلّب أغلب الواجهات البرمجية لخدمات الطقس التسجيل. سنضيف خدمة Weather Underground، لذا سجّل في هذه الخدمة واعثر على مفاتيح الاستيثاق الضرورية لاستخدام واجهة التطبيقات البرمجية. بما أننا نريد أن نحصُل على نفس السلوك من جميع الخدمات فسيكون من المجدي كتابة هذا السلوك في واجهة. type weatherProvider interface { temperature(city string) (float64, error) // in Kelvin, naturally } يمكننا الآن تحويل دالة الاستعلام من openWeatherMap السابقة إلى نوع بيانات يوافق الواجهة weatherProvider. بما أننا لا نحتاج لحفظ أي حالة لإجراء طلب HTTP GET فسنستخدم بنية struct فارغة، وسنضيف سطرا قصيرا في دالة الاستعلام الجديدة لتسجيل ما يحدُث عند الاتصال بالخدمات لمراجعته في ما بعد: type openWeatherMap struct{} func (w openWeatherMap) temperature(city string) (float64, error) { resp, err := http.Get("http://api.openweathermap.org/data/2.5/weather?APPID=YOUR_API_KEY&q=" + city) if err != nil { return 0, err } defer resp.Body.Close() var d struct { Main struct { Kelvin float64 `json:"temp"` } `json:"main"` } if err := json.NewDecoder(resp.Body).Decode(&d); err != nil { return 0, err } log.Printf("openWeatherMap: %s: %.2f", city, d.Main.Kelvin) return d.Main.Kelvin, nil } لا نريد سوى استخراج درجة الحرارة (بالكلفن) من الإجابة، لذا يمكننا تعريف بنية struct على السطر Inline. في ما عدا ذلك فإن الشفرة البرمجية مشابهة لدالة الاستعلام السابقة، ولكنّها معرَّفة على صيغة تابع Method لبنية openWeatherMap. تتيح لنا هذه الطريقة استخدام عيّنة Instance من openWeatherMap مكان الواجهة weatherProvider. سنفعل نفس الشيء بالنسبة لخدمة Weather Underground. الفرق الوحيد مع الخدمة السابقة هو أننا سنخزّن مفتاح الواجهة البرمجية في بنية struct ثم نستخدمه في التابع. يجدر ملاحظة أن Weather Underground لا تعالج أسماء المدن المتطابقة بنفس جودة تعامل Open WeatherMap، وهو ما ينبغي الانتباه إليه في التطبيقات الفعلية. لن نعالج هذا الأمر في مثالنا البسيط هذا. type weatherUnderground struct { apiKey string } func (w weatherUnderground) temperature(city string) (float64, error) { resp, err := http.Get("http://api.wunderground.com/api/" + w.apiKey + "/conditions/q/" + city + ".json") if err != nil { return 0, err } defer resp.Body.Close() var d struct { Observation struct { Celsius float64 `json:"temp_c"` } `json:"current_observation"` } if err := json.NewDecoder(resp.Body).Decode(&d); err != nil { return 0, err } kelvin := d.Observation.Celsius + 273.15 log.Printf("weatherUnderground: %s: %.2f", city, kelvin) return kelvin, nil } لدينا الآن مزوّدا خدمة طقس. فلنكتب دالّة تستعلم من الاثنين وتعيد متوسّط درجة الحرارة. سنكفّ - حفاظا على بساطة المثال - عن الاستعلام إذا واجهتنا مشكلة في الحصول على بيانات من الخدمتين. func temperature(city string, providers ...weatherProvider) (float64, error) { sum := 0.0 for _, provider := range providers { k, err := provider.temperature(city) if err != nil { return 0, err } sum += k } return sum / float64(len(providers)), nil } لاحظ أن تعريف الدالة قريب جدّا من تعريف التابع temperature المُعرَّف في الواجهة weatherProvider. إن جمعنا الواجهات weatherProvider في نوع بيانات ثم عرّفنا تابعا باسم temperature على هذا النوع فسيمكننا إنشاء نوع جديد يجمع الواجهات weatherProvider. type multiWeatherProvider []weatherProvider func (w multiWeatherProvider) temperature(city string) (float64, error) { sum := 0.0 for _, provider := range w { k, err := provider.temperature(city) if err != nil { return 0, err } sum += k } return sum / float64(len(w)), nil } رائع! سنتمكّن من تمرير multiWeatherProvider إلى أي دالة تقبل weatherProvider. نربُط الآن خادوم HTTP بدالة temperature للحصول على درجات الحرارة عند طلب مسار به اسم مدينة: func main() { mw := multiWeatherProvider{ openWeatherMap{}, weatherUnderground{apiKey: "your-key-here"}, } http.HandleFunc("/weather/", func(w http.ResponseWriter, r *http.Request) { begin := time.Now() city := strings.SplitN(r.URL.Path, "/", 3)[2] temp, err := mw.temperature(city) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") json.NewEncoder(w).Encode(map[string]interface{}{ "city": city, "temp": temp, "took": time.Since(begin).String(), }) }) http.ListenAndServe(":8080", nil) } صرّف البرنامج، شغّله واطلب رابط خادوم الوب كما فعلنا سابقا. ستجد - علاوة على الإجابة بصيغة JSON في نافذة الطلب - مُخرجات قادمة من تسجيلات الخادوم التي أضفناها أعلاه في النافذة التي شغّلت منها البرنامج. ./hello 2015/01/01 13:14:15 openWeatherMap: tokyo: 295.46 2015/01/01 13:14:16 weatherUnderground: tokyo: 273.15 $ curl http://localhost:8080/weather/tokyo {"city":"tokyo","temp":284.30499999999995,"took":"821.665230ms"} جعل الاستعلامات تعمل بالتوازي نكتفي لحدّ الساعة بالاستعلام من الواجهات البرمجية بالتتالي، الواحدة تلو الأخرى. لا يوجد ما يمنعنا من الاستعلام من الواجهتيْن البرمجيّتين في نفس الوقت، وهو ما سياسهم في تقليل الوقت اللازم للإجابة. نستفيد من إمكانات Go في التشغيل المتزامن عبر وحدات Go الفرعية goroutines والقنوات Channels. سنضع كل استعلام في وحدة فرعية خاصّة به ثم نشغّلها بالتوازي. نجمع الإجابات بعد ذلك في قناة واحدة ثم نحسب المعدّلات عندما تكتمل جميع الاستعلامات. func (w multiWeatherProvider) temperature(city string) (float64, error) { // ننشئ قناتيْن، واحدة لدرجات الحرارة والأخرى للأخطاء // يُضيف كل مزوّد خدمة قيمة إلى إحدى القناتيْن فقط temps := make(chan float64, len(w)) errs := make(chan error, len(w)) // نطلق بالنسبة لكلّ مزوّد خدمة وحدة فرعية جديدة بدالة مجهولة الاسم. تستدعي الدالة مجهولة الاسم التابع temperature ثم تعيد توجيه النتيجة المتحصًّل عليها. for _, provider := range w { go func(p weatherProvider) { k, err := p.temperature(city) if err != nil { errs <- err return } temps <- k }(provider) } sum := 0.0 // نجمع درجات الحرارة - أو الأخطاء في حالة وجودها - من كل خِدمة for i := 0; i < len(w); i++ { select { case temp := <-temps: sum += temp case err := <-errs: return 0, err } } // نُرجع الحرارة كما في السابق return sum / float64(len(w)), nil } يساوي الوقت اللازم الآن لتنفيذ جميع الاستعلامات المدة الزمنية اللازمة للحصول على إجابة من أبطأ خدمة طقس؛ بدلا من مجموع المدد الزمنية لجميع الاستعلامات كما كان سابقا. كل ما احتجنا له هو تعديل سلوك multiWeatherProvider الذي ما زال مع ذلك يُرضي حاجات واجهة weatherProvider البسيطة وغير المتوازية. السهولة انتقلنا ببضع خطوات وبالاقتصار فقط على المكتبة المعيارية لـGo من مثال “hello world” إلى خادوم سند خلفي Backend server يحترم مبادئ REST. يمكن نشر الشفرة التي كتبناها على أي معمارية خواديم تقريبا. الملف التنفيذي الناتج سريع ويتضمّن جميع ما يحتاجه للعمل؛ والأهم من ذلك، الشفرة البرمجيّة واضحة لقراءتها وفهمها. كما تمكن صيانتها وتمديدها بسهولة حسب الحاجة. أنا مقتنع أن كلّ هذه الميزات هي نتيجة لتفاني Go في البساطة. ترجمة - بتصرّف - للمقال How I start Go لصاحبه Peter Bourgon.
  3. تتبنّى لغة البرمجة Go مفتوحة المصدر التي تطوّرها شركة Google، والتي يُشار إليها أحيانا بـ Golang، تتبنّى مقاربة تقليلية Minimalist في تطوير البرمجيّات تسمح بكتابة برامج سهلة، موثوقة وفعّالة. يساعدك هذا الدرس في تثبيت الإصدار 1.8 من Go (الإصدار المستقرّ الأحدث حتى الساعة) على خادوم Centos 7، وتصريف Compiling برنامج “Hello, World!” بسيط. المتطلّبات يُستحسن أولا التأكد من وجود مستخدم إداري غير المستخدم الجذر على الخادوم. تمكنك معرفة كيفية ضبط مستخدم بهذه المواصفات بقراءة هذا الدرس لتعرف كيف تنشئ مستخدما بصلاحيات sudo على Centos. الخطوة الأولى: تثبيت Go نذهب إلى الموقع الرسمي للحصول على آخر إصدار من Go. تأكّد من تنزيل حزمة لينكس الموافقة لمعمارية 64 بت. نبدأ بالانتقال إلى مجلّد تمكننا الكتابة فيه: cd /tmp نستخدم الأمر curl ونمرّر له رابط حزمة Go الذي تحصّلنا عليه من الموقع الرسمي للغة: curl -LO https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz على الرغم من أننا متأكدون من المصدر الذي نزّلنا منه الملف، إلا أنه من الجيّد التحقّق من سلامة الملفات وموثوقيّتها عند تنزيلها من الإنترنت. يوفّر موقع Go قيمة التجزئة Hash لكلّ ملف مضغوط على صفحة التنزيلات. ننفّذ الأمر التالي لحساب قيمة التجزئة الخاصّة بالملفّ الذي نزّلناه: shasum -a 256 go1.8*.tar.gz تشبه نتيجة الأمر التالي: 1862f4c3d3907e59b04a757cfda0ea7aa9ef39274af99a784f5be843c80c6772 go1.8.3.linux-amd64.tar.gz قارن قيمة التجزئة التي تحصّلت عليها مع تجزئة الملف الموجودة على صفحة تنزيلات Go. توجد قيمة تجزئة لكلّ ملف على صفحة التنزيلات، لذا تأكد من التجزئة الصحيحة. ننتقل بعد تنزيل Go والتأكد من سلامة البيانات إلى تثبيت بيئة تصريف اللغة. الخطوة الثانية: تثبيت Go يتمثّل تثبيت Go في استخراج محتويات الملفّ المضغوط وحفظها في المجلّد usr/local/. يحفظ الأمر tar محتويات الملّف بعد استخراجها على المسار المُمرَّر بعد الخيار C-. يُستخدَم الخيار x- لفك ضغط الملف، v- لإظهار مُخرجات تفصيلية لعمل الأمر ويُحدّد z- الخوارزميّة المستخدمة لضغط الملف (gzip)؛ أما الخيار f- فيحدّد الملف المضغوط الذي نستخرج محتوياته: sudo tar -C /usr/local -xvzf go1.8.3.linux-amd64.tar.gz ملحوظة: تنصح Google بوضع مجلّد Go على المسار usr/local/. لا يمنع وضع المجلّد على مسار آخر إمكانية استخدام اللغة، إلا أن المسار المُخصَّص يجب أن يُعرَّف ضمن متغيّر البيئة GOROOT. تشرح الخطوة المواليّة ضبط المسارات. سننشئ في ما يلي مجلّد عمل جديدا لـGo داخل المجلّد الشخصي للمستخدم، وننشئ فيه ثلاثة مجلدات فرعية src،bin وpkg. سيحوي المجلّد الفرعي bin البرامج التنفيذية الناتجة عن تصريف ملفات الشفرة البرمجية الموجودة في المجلّد src. لن نستخدم في هذا الدرس المجلّد pkg إلا أنه مفيد في المشاريع المتقدّمة إذ يخزّن الحزم وهي مجموعة من الشفرات البرمجية التي يمكن تشاركها بين البرامج. سنسمّي مجلّد العمل projects، إلا أن بإمكانك تسميته بالاسم الذي تريد. يؤدّي استخدام الخيار p- مع الأمر mkdir إلى إنشاء المجلّدات وفق الهرميّة الموجودة في المسار المُمرَّر للأمر. mkdir -p ~/projects/{bin,pkg,src} يصبح Go جاهزا للعمل باكتمال هذه الخطوة، إلا أن استخدامه يتطلّب ذكر مسار التثبيت كاملا في سطر الأوامر. يمكن أن نجعل الاستخدام أكثر سهولة بضبط بضعة مسارات، وهو ما سنفعله في الخطوة التالية. الخطوة الثالثة: ضبط مسارات Go سنحتاج لإدراج المسار الذي ثبّتنا عليها Go إلى متغيّر البيئة PATH$ حتى يمكننا تنفيذه بنفس طريقة تنفيذ أي أمر في الطرفية: ذكر اسم الأمر فقط، دون المسار الكامل. بما أن Go مثبَّت في مجلّد يستخدمه نظام التشغيل فسنضبُط Go ليكون متاحا لجميع المستخدمين. أنشئ سكريبت باسم path.sh على المسار etc/profile.d/ باستخدام محرّر النصوص vi: sudo vi /etc/profile.d/path.sh أضف السطر التالي إلى آخر الملف ثم احفظ الملف وأغلقه: export PATH=$PATH:/usr/local/go/bin تنبيه: عدّل المسار بما يُناسب إن كنت قد اخترت مكانا مختلفا لتثبيت Go. نعرّف أيضا قيمتيْ المتغيّريْن GOPATH وGOBINفي ملّف المستخدم bash_profile. للإشارة إلى مجلّد العمل الذي أنشأناه في الخطوة السابقة. يحدّد المتغيّر GOPATH مكان ملفات الشفرة البرمجية بينما يحدّد المتغيّر GOBIN المجلّد الذي يجب أن توضع فيه الملفات التنفيذية بعد تصريف الشفرات البرمجية. نفتح الملف bash_profile.: vi ~/.bash_profile نضيف السطريْن التاليّيْن إلى نهاية الملف: export GOBIN="$HOME/projects/bin" export GOPATH="$HOME/projects/src" تنبيه: إن كان Go مثبّتا على مسار غير المسار المنصوح به (usr/local/) فيجب أن تعرّف قيمة المتغيّر GOROOT في الملفّ bash_profile. إلى جانب المتغيّريْن GOBIN وGOPATH: export GOROOT="/path/to/go" export GOBIN="$HOME/projects/bin" export GOPATH="$HOME/projects/src" حيث path/to/go/ مسار تثبيت Go. ننفّذ الأمر source لاعتماد التغييرات على الملفات التي عدّلناها وإعادة تحميلها لجلسة الطرفية الحالية: source /etc/profile && source ~/.bash_profile يجب أن يكون كلّ شيء جاهزا الآن، وهو ما سنتأكّد منه في الخطوة التالية. الخطوة الرابعة: كتابة برنامج Go واختباره نهدف من هذه الخطوة إلى التأكد من أن بيئة Go جاهزة للعمل على جهازنا. نبدأ بإنشاء ملفّ جديد لنضع فيه أول شفرة برمجيّة نكتبها: vi ~/projects/src/hello.go تستخدم شفرة Go أدناه حزمة main، تستورد مكتبة fmt لدوالّ الإدخال والإخراج وتضبُط دالة جديدة لطباعة الجملة !Hello, World. package main import "fmt" func main() { fmt.Printf("Hello, World!\n") } احفظ الملف ثم أغلقه. ثم نصرّف الشفرة البرمجية بالأمر go install: go install $GOPATH/hello.go نحن الآن جاهزون لتشغيل البرنامج: $GOBIN/hello إن كان كل شيء على ما يُرام فستظهر رسالة Hello, World! بعد تشغيل البرنامج. نتأكد بتنفيذ برنامج Hello, World! السابق من أن بيئة Go مثبّتة وجاهزة للاستخدام. تستخدم برامج Go عادة مكتبات برمجية وحزما خارجية. راجع مقالات البرمجة بلغة Go للمزيد عن كيفية كتابة البرامج بهذه اللغة. ترجمة - بتصرّف - للمقال How To Install Go 1.7 on CentOS 7 لصاحبه Michael Lenardson.
  4. كيف تبدو البرمجة بلغة Go؟ وكيف أقوم بتشغيل برنامج كُتب بـ Go؟ هذا ما سنتعرف عليه خلال هذا الدرس من سلسلة مدخل إلى لغة البرمجة Go، وقبل متابعة الدرس، أحب أن أتأكد أنك تابعت الدرسين السابقين منها أولا. أهلا بالعالمسنحاول اتباع العادة التي جرت عليها دروس تعلم لغات البرمجة، وهي ببساطة كتابة جملة "أهلا بالعالم" (بالانجليزية "Hello World") باللغة المُراد تعلمها، ببساطة هذا ما سيبدو عليه برنامج أهلا بالعالم في Go: package main import "fmt" func main() { fmt.Print("أهلا بالعالم\n") }ضع هذا في ملف باسم helloworld.go داخل مجلد باسم hellogo مثلا، تحت مسار: $GOPATH/src/github.com/YOUR_USER/حيث GOPATH$ هو مسار بيئة عملك، راجع الدرس الثاني لتفهم آلية عمله.غيّر YOUR_USER إلى اسم مستخدمك على github.com مثلا أو أحد خدمات إدارة الشفرة البرمجية.بالتالي سيكون المسار النهائي للملف الجديد الذي أنشأناه هو: $GOPATH/src/github.com/YOUR_USER/hellogo/helloworld.goكل ما عليك فعله الآن هو التنقل إلى مسار الملف وكتابة أمر go run helloworld.go $ go run helloworld.go أهلا بالعالمإذا كانت طرفية سطر الأوامر لديك لا تدعم اللغة العربية، فقد تجد أن الكتابة العربية مقلوبة والحروف متقطعة، لا بأس بذلك حاليا، لكن لاحظ أن Go قبلت بالحروف العربية داخل نص الشفرة البرمجية وتعاملت معها بشكل عادي، ذلك لأن كل شيء تعتبره unicode افتراضا. لنشرح البرنامج سطرًا بسطر: package mainببساطة: لابد لكل ملف شيفرة برمجية في Go أن ينتمي إلى حزمة (package) ما.ولابد لكل حزمة في Go أن تنتمي إلى مجلد ما.لا يمكن لحزمتين التواجد على مستوى نفس المجلد، لكن يمكن لعدة ملفات أن تنتمي إلى نفس الحزمة (يعني مجلد به عدة ملفات)، كما يمكن أن تتواجد حزمة داخل حزمة أخرى لكن كلٌ في مجلد فرعي على حِدى.في مثالنا السابق، أعطينا main كاسم لحزمتنا، وهو اسم خاص، حيث يُعامل مُجمّع (compiler) لغة Go هذه الحزمة على أنها مدخل البرنامج (program entry)، أي أن التعليمات الموجودة في هذه الحزمة يتم تشغيلها أولا. أسبقنا اسم الحزمة بالكملة المفتاحية package. import "fmt"import: كلمة مفتاحية أخرى وتعني "استرِد" أو "اجلِب" المكتبة الفلانية أو الحزمة الفلانية."fmt" اختصار لـ format أو formatting وهي مكتبة قياسية (standard library) تأتي مع تنصيب Go، خاصة ببناء وطباعة النص. لاحظ أن اسم المكتبات أو الحزم المُراد استيرادها دائما ما يتم إحاطتها بعلامة اقتباس "".func main() {هنا قمنا بإنشاء دالة تحمل اسم main: لإنشاء الدالة استعملنا الكملة المفتاحية func ثم مسافة، ثم اسم الدالة.مثل حزمة main فإن دالة main أيضا يعاملها المجمع (Compiler) معاملة خاصة، حيث تعتبر هي نقطة دخول البرنامج (Entry point)، أي أن التعليمات الموجودة في هذه الدالة تحديدا، داخل حزمة main تحديدًا، يتم تشغيلها أولا، إلا في حالة وجود دالة أخرى باسم ()init والتي سنتعرض لها في دروس أخرى.مثل جافاسكريبت وباقي اللغات، فإن } يفتح جسم الدالة (function body).fmt.Print("أهلا بالعالم\n")هنا قمنا باستعمال حزمة "fmt" التي قمنا باستيرادها أعلاه، لاستعمال أي حزمة في Go يكفي كتابة اسمها، ثم نقطة، ثم اسم الدالة التي تريدها استعمالها من تلك الحزمة، في حالتنا هذه، أردنا ببساطة طباعة نص "أهلا بالعالم" والرجوع إلى السطر، لذلك استعملنا دالة Print ومررلنا لها القيمة "n\أهلا بالعالم":مررنا القيمة بين علامتي اقتباس "" ﻷنها عبارة عن سلسلة نصية (string).أنهينا سلسلتنا النصية بعلامة n\ وهي علامة خاصة في أغلب لغات البرمجة، وتعني "سطر جديد"، استعملناها للرجوع إلى السطر.نُمرّر القيم والمعاملات للداوال عبر وضعها بين قوسين مباشرة بجنب اسم الدالة.}أغلقنا جسم الدالة main باستعمال علامة {، أي أن تعليمات هذه الدالة قد انتهت.لاحظ غياب علامة الفاصلة المنقوطة ";" بعد نهاية كل تعليمة، لا حاجة لها في Go.مفهوم الحزم (Packages) في Goالحزم (packages) طريقة بسيطة لتجزئة برنامجك إلى أجزاء أصغر مُقسّمة حسب الغرض أو الوظيفة، يُمكن الاشارة للحزم على أنهم "مكتبات" (libraries) أو وحدات (modules)، تركيب الحزم مع بعضها يشكل مُجمل برنامجك. تتبع Go القواعد التالية في كيفية تقسيم برنامج إلى حزم: الحزمة غالبا عبارة عن مجلد داخل مشروعك به الملفات التي تحمل اسم الحزمة.لابد من وجود حزمة واحدة على الأقل في أي برنامج أو مكتبة.إذا كان البرنامج عبارة عن برنامج تنفيذي (وليس مكتبة - library) فإنه يجب وجود حزمة باسم main (أي package main) تكون هي مدخل البرنامج كما رأيناه في مثالنا الأول.وكتذكير لما ذكرناه سابقا: لابد لكل ملف شفرة برمجية في Go أن ينتمي إلى حزمة (package) ما.ولابد لكل حزمة في Go أن تنتمي إلى مجلد ما.لا يمكن لحزمتين التواجد على مستوى نفس المجلد، لكن يمكن لعدة ملفات أن تنتمي إلى نفس الحزمة (يعني مجلد به عدة ملفات).يمكن أن تتواجد حزمة داخل حزمة أخرى لكن كلٌ في مجلد فرعي على حِدى.يمكن للمجلد الرئيسي لمشروعك أن يحتوي على حزمة ما، واحدة فقط، باقي الحزم الخاصة به يمكنها أن تتواجد في مجلدات فرعية.غياب حزمة main من برنامج ما، يجعل منه مكتبة فقط وليس برنامجا تشغيليا قائما بحد ذاته.عند كتابة الحزم، أي اسم دالة أو متغير أو بُنية (Struct) يبدأ بحرف كبير (Uppercase) يعني أن هذه الدالة/المتغير/البنية متوفر بشكل عام لجميع من يقوم باستيراد هذه الحزمة عبر الكلمة المفتاحية import. وأي اسم دالة/متغير يبدأ بحالة أحرف صغيرة (Lowercase) يعني أنه خاص ولن يتم تصديره (لن يكون متاحا) لباقي الحزم والبرامج. في مثالنا السابق، وفّرت حزمة "fmt" دالة Print لنا بشكل مُتاح، لاحظ أن Print تبدأ بحرف P كبير (Uppercase). وكان فقط يكفي كتابة (...)fmt.Print مكتبة (حزمة) أهلا بالعالمماذا لو أردنا قول "أهلا بالعالم" في أكثر من مشروع؟ ربما سيكون من الأمثل جعل طباعة "أهلا بالعالم" في مكتبة مستقلة نقوم باستيرادها في مشاريع أخرى، هذا مثال فقط لكيفية بناء مكتبة في Go، فطبعا لن تحتاج إلى مكتبة كل ما تقوم به هو "أهلا بالعالم". دعنا نحاول كتابة هذا في دالة بسيطة، نسميها SayHello ولنضها في حزمة خاصة، نسميها sayhello. دعنا نبني هذه المكتبة في مشروع مستقل، لتكون مكتبة يُمكن جلبها في أكثر من برنامج أو مشروع آخر. سنسمي المشروع sayhello، أي بنفس اسم الحزمة لتسهيل الأمر. لن نحتاج إلى package main ﻷننا سنبني مكتبة فقط وليس برنامجا تنفيذيا في حد ذاته. بالتالي قم بإنشاء مجلد مشروع جديد تحت مسار: $GOPATH/src/github.com/YOUR_USER/بنفس الطريقة التي شرحناها سابقا. أنشئ ملفا باسم sayhello.go تحت مجلد sayhello، ليكون مسار الملف أشبه بهذا: $GOPATH/src/github.com/YOUR_USER/sayhelo/sayhello.goوالآن، نفتح ملف sayhello.go بمحرر النصوص المفضل لديك ثم نشرع في كتابة دالتنا المذهلة، لا يُفترض بك فهم كل شيء حاليا، فالغرض شرح مفهوم الحزم والمكتبات، مع ذلك سنحاول شرح تعليمات هذه الدالة: package sayhello // SayHello returns Hello World in Arabic. func SayHello() string { return "أهلا بالعالم\n" } لاحظ أن دالتنا لا تختلف كثيرًا عن برنامج "أهلا بالعالم" الذي كتبناه أول مرة: استعملنا package sayhello عوض package main.سمينا الدالة ()func SayHello عوض ()func main. لاحظ أننا جعلنا اسم الدالة يبدأ بحرف كبير (Uppercase) ذلك ﻷننا نريد تصدير هذه الدالة وإتاحتها لباقي المشاريع التي تسترد حزمة sayhello.قمنا بتصريح أن الدالة تُرجع سلسلة نصية عبر كتابة الكلمة المفتاحية string على يمين الدالة.قمنا بإرجاع السلسلة النصية "n\أهلا بالعالم" عبر الكلمة المفتاحية return عوض طباعتها باستخدام مكتبة fmt كما فعلنا أول مرة.أصبح الآن لدينا "أهلا بالعالم" في شكل مكتبة! لكن كيف نجعلها قابلة للجلب؟ أي كيف نضعها في مجلد pkg حتى تستطيع باقي المشاريع جلبها والاستفادة منها؟ كل ما علينا فعله هو كتابة go install داخل مجلد مشروع sayhello. طبعا لن يكون بإمكانك تشغيل هذه المكتبة عبر أمر go run sayhello.go مثل ما فعلنا أو مرّة، ﻷن ما قمنا بكتابته هذه المرة عبارة عن مكتبة وليس برنامجًا تنفيذيًا! فحص مكتبة "أهلا بالعالم"هل تعمل دالتنا بشكل جيد؟ كيف يمكن التحقق من برامجنا وحزمنا التي نكتبها في Go؟ هل مكتبة "أهلا بالعالم" تطبع حقا "أهلا بالعالم"؟ دعنا نتأكد من ذلك عبر كتابة فحص مؤتمت لهذه الدالة! في لغة Go: يمكن كتابة فحوصات واختبار وحدات (Unit testing) بسهولة، يكفي إنشاء ملف بنفس اسم الملف المُراد اختباره مع إضافة test_ له.يمكن فحص دالة معينة بمجرد كتابة Test ثم اسم الدالة.في حالتنا هذه، وفي نفس مسار مشروع sayhello أنشئ ملفا باسم sayhello_test.go بجانب ملف sayhello.go نفسه لنقوم باختبار حزمة sayhello. افتح ملف sayhello_test.go بمحرر النصوص المفضل لديك. كل ما علينا فعله لتجربة دالتنا هو جلبها وفحص إذا كانت نتيجة الطباعة هي فعلا "أهلا بالعالم"! كما هو موضح في الشفرة التالية: package sayhello import "testing" func TestSayHello(t *testing.T) { greeting := SayHello() if greeting != "أهلا بالعالم\n" { t.Error("TEST FAILED!") } } في الشِيفرة أعلاه: قمنا باستيراد حزمة "testing" القياسية التي توفرها لغة Go بشكل افتراضي لأغراض إنشاء الفحوصات المؤتمتة.بما أننا نريد فحص دالة SayHello قمنا بإنشاء دالة TestSayHello مع تمرير testing.T لها، أي أن هذه الدالة تُعتبر "حالة فحص"، لا يجب عليك فهم هذا التعبير حاليا، يمكنك تجاهله، الغرض هو فهم آلية عمل الفحوصات المؤتمتة في Go.داخل هذه الدالة الفاحصة، قمنا ببساطة بنداء دالتنا SayHello وفحص إذا كانت القيمة التي تُرجعها عبارة عن "n\أهلا بالعالم" فإن كانت كذلك، يمر الفحص بسلام ولن نطبع أي شيء، وإن لم تكن كذلك، نطبع "!TEST FAILED" باستخدام المعامل t التابع لحزمة testing القياسية باستعمال الدالة Error، والتي تُخبر بدورها أن حالة الفحص هذه قد فشلت. الآن، في نفس المجلد الذي أنت به يكفي كتابة go test لفحص حزمة sayhello الخاص بنا! يُفترض أن تتلقى نتيجة مشابهة لهذه: PASS ok github.com/01walid/sayhello 0.001sيمكن إضافة v- أو cover-- إلى الأمر السابق لطباعة المزيد من المعلومات حول الفحوصات التي يقوم بها المُجمع، مثلا go test -v --cover === RUN TestSayHello --- PASS: TestSayHello (0.00s) PASS coverage: 100.0% of statements ok github.com/01walid/sayhello 0.001s لاحظ أننا تحصلنا على coverage: 100.0%! أي أن الفحوص التي قمنا بها تغطي جميع الدوال التي قمنا بكتابتها في هذا المشروع (بما أن لدينا دالة واحدة فقط وفحص واحد، فالنتيجة طبيعية)، من المستحسن دائما إبقاء نسبة تغطية الفحوصات مرتفعة في برامجك، حتى تضمن أن استقرارها جيد ويمكن التعويل عليها. إنشاء توثيق لمكتبة "أهلا بالعالم"أنهينا مكتبتنا المذهلة، تأكدنا من صحة عملها، ماذا لو أمكننا توليد ومشاركة توثيق لها؟ لن تحتاج الكثير لفعل ذلك! كل ما عليك فعله هو كتابة الأمر godoc -http=:6060 ثم زيارة localhost:6060 على متصفحك! ستحتاج إلى التنقل إلى توثيق مكتبتك بشكل خاص عبر زيادة http://localhost:6060/pkg/github.com/YOUR_USER/sayhello/طبعا قم بتغيير YOUR_USER إلى اسم المستخدم الخاص بك، تماما مثل مسار المكتبة في بيئة GOPATH$ الخاص بك. استعمال مكتبة "أهلا بالعالم"دعنا نستعمل هذه المكتبة في برنامجنا الأول، سنحتاج إلى تغييرات بسيطة لجعله يستغل مكتبة "أهلا بالعالم" كما هو موضح (تذكر: مشروعنا الأول في مجلد لوحده باسم sayhello): package main import "fmt" import "github.com/01walid/sayhello" func main() { fmt.Print(sayhello.SayHello()) } قمنا فقط بجلب مكتبتنا الجديدة عبر كتابة: import "github.com/YOUR_USER/sayhello"ثم استعمالها عبر مناداة دالة SayHello منها داخل fmt.Print عوض كتابة "أهلا بالعالم" مباشرة: fmt.Print(sayhello.SayHello())الآن شغّل البرنامج مجددا عبر كتابة go run helloworld.go، هذا كل ما في الأمر! تهانينا لك أول برنامج وأول مكتبة لك باستخدام لغة البرمجة Go! إضافة (Bonus)في إضافة هذا الدرس، اخترت أن أشير إلى بعض إضافات محررات النصوص البرمجية الشهيرة، والتي من شأنها أن تسهل عليك البرمجة بـ Go بشكل معتبر. ستجد من هنا قائمة بهذه الإضافات، مثلا إن كنت من مستعملي SublimeText فقم بتنصيب إضافة GoSublime وإن كنت من مستعملي محرر Atom فقط بتنصيب Go-plus. خاتمةتعرفنا في هذا الدرس على كيفية كتابة برنامج باستخدام لغة Go، ثم جعل البرنامج على شكل مكتبة عوض تركه في شكله التنفيذي. من المهم جعل برامجك عبارة عن مجموعة مكتبات منفصلة حسب الغرض، عوض جعل كل شيء متداخل في حزمة واحد أو في برنامج تنفيذي. فكما رأينا إنشاء برنامج تنفيذي أسهل ما يكون، إذ يكفي كتابة ملف به package main ثم func main واستدعاء باقي الحزم، بالتالي الأهم من ذلك هو التفكير التجريدي وفصل المهام عن بعضها في مكتبات وحزم حسب الغرض، كلٌ يقوم بمهمة/غرض ما، ويقوم به بشكل جيد ومُختبر (unit tests). في درسنا هذا، كانت المكتبة منفصلة تماما عن البرنامج التنفيذي. مشاريعك القادمة ستكون على الأغلب مقسمة إلى حزم/مكتبات داخل مجلد المشروع نفسه وليس بالضرورة في مجلد/مشروع آخر، لكن المفهوم هو نفسه. رأينا أيضا، أن التعليقات في Go وسيلة ممتازة لتوليد التوثيق بأدنى جهد، لذلك يجدر بك كمبرمج عدم إهمالها والاهتمام بها وبتفاصيلها. كل هذا كان سهلا! لعلك كنت تسمع بهذه الأمور فتفزع (tests, docs, cover.. الخ) لكني قدمت هذه المفاهيم عمدا في الدروس الأولى لترى أن لا شيء يستحق الهروب منه. وأن البرامج ذات الجودة العالية مجرد اتباع لسلوكيات مهذبة وممارسات محبذة بخطوات ثابتة ينبغي أن تُعوّد نفسك عليها من الآن وتجعل منها أسلوب تطوير/برمجة. في الدروس القادمة سنتطرق إلى أنواع المتغيرات، هيكلة البيانات، كيفية إنشاء متغير، الحلقات والجمل الشرطية.
  5. لعلّك سمعت في السنوات القليلة الماضية عن لغة برمجة جديدة نشأت من داخل شركة Google تحمل اسم Go (أو Golang كمصطلح قابل للبحث على محركات البحث)، سنحاول من خلال هذه السلسلة التعرّف على هذه اللغة، مزاياها، عيوبها وما يجعلها مختلفة عن غيرها. سيكون الدرس الأول من هذه السلسلة درسًا كلاميا فقط، يركز على نقاط اختلاف اللغة مع باقي اللغات، وهو موجه لمن له خلفية برمجية نوعا ما مع باقي اللغات، لكن ستكون باقي الدروس موجهة للمبتدئين. كعادة كل عقد من الزمن، فإنه تظهر هناك أدوات وتقنيات جديدة تحاول الاستفادة من أخطاء أسلافها من الأدوات والتقنيات، هذا يشمل لغات البرمجة أيضا، لذلك دعك من قول "لماذا لغة برمجة جديدة؟" و "ما الحاجة للغة برمجة جديدة؟" أو "لماذا لا يتفقون على لغة برمجة واحدة؟"، فما لغة البرمجة إلا أداة تقضي بها مهامك، وكل منها يكون أصلح لنوع مهام ما. فاختر لكل مهمة أنسب أداة، ولا داعي لتقديس الأداة وإنشاء الحروب الكلامية -غير التقنية- حولها أو خلق هاجس وهمي يحول عن تعلمها. أَحَسَّ فريقٌ من المبرمجين (العريقين) من داخل Google أنه حان الوقت لتحسين سير عملهم بلغة C و ++C، وأنهم يحتاجون إلى أداة جديدة تلغي عيوب هاتين الأخيرين وتحسن من إنتاجيتهم أكثر، وتكون ملائمة لنوعية احتياجات Google الحسابية. أسسوا لغة البرمجة Go داخل Google عام 2007. الفريق العريق المؤسس لهذه اللغة يشمل مؤسس نظام Unix نفسه Ken Thompson (عَلَمٌ في عِلم الحاسوب، يُعرف اختصارًا بـ Ken) الذي عمل لدى Bell Labs، كذلك Robert Pike الذي كان أيضا من ضمن فريق Unix لدى Bell Labs وأحد مؤسسي ترميز UTF-8 وأخيرًا Robert Griesemer أحد العاملين على محرك جافاسكريب V8. Ken على يسار الصورة بجانب Dennis Ritchie مؤسس لغة C بمعرفة هذه النبذة التاريخية البسيطة عن Go، أحب أن أقتل فيك كل حماس مُفرط، فلا أحب منك أن تعشق لغة برمجة بسبب مؤسيسها، أو أنها خرجت من شركة تحبها، لذلك سأبدأ بسرد أشياء قد لا تحبها حول لغة البرمجة Go، حتى إذا قرأتها ولم تعجبك، فقد يجدر بك التوقف عن القراءة حينها. سأكون سعيدا شخصيا بمتابعة عدد قليل جدا من القراء لهذه السلسلة يدركون حقا ما يفعلون، عوض زخم يتحمس لكل جديد دون وعي وإلمام بالأمور. أشياء قد لن تحبها حول لغة البرمجة Go1. ليست كائنية التوجههذا إن كنت تظن أنها كذلك، فلا يوجد مفهوم الصنف (Class) ولا الكائنات (Objects) وبالتالي لا يوجد وراثة (inheritance). مع ذلك فإن Go تحمل بضعا من مزايا البرمجة الكائنية كتوفيرها لـ Interface و دوال البنيات (Struct methods) وتركيب البنيات (Struct composition). لماذا؟ مؤسسي اللغة يرون أن اللغات كائنية التوجه تحمل العديد من العيوب والتعقيدات التي يمكن إلغاؤها بالتخلي عن بعض هذه المفاهيم كلية. حتى مبرمجي Java أنفسهم ينصحون بـ Composition مثلا في كثير من الأحيان عوض inheritance، مؤسسي اللغة ممن يرون أن البرمجة كائنية التوجه غالبا ما تكون فكرة سيئة -تقنيا-. 2. لا توجد معالجة للاستثناءات Exception Handlingقد تكون هذه نتيجة طبيعية بسبب غياب مفهوم البرمجة الكائنية لدى Go، فمعالجة الأخطاء في Go تتم بطريقة واضحة وتقليدية نوعا ما، حيث أن الأخطاء تُرجع كقيم عادية من نوع error. حيث error هو نوع بدائي في حد ذاته مثله مثل أي نوع أصلي آخر (int, string .. الخ). مع ذلك تسمح لك Go بقذف خطأ للحالات الاستثنائية عبر الكلمة المفتاحية panic (أشبه بـ raise أو throw في باقي اللغات) وكذا التعافي من هذه الأخطاء عن طريق recover. 3. لا توجد معامِلات افتراضية أو اختيارية يمكن تمريرها للدوال (default/optional arguments)ربما قد اعتدت في لغات البرمجة الأخرى على القيام بشيء مثل: function listFolders(path, subfolders=false, recursive=false){ ... } لكن في Go لن يمكنك تمرير subfolder=false ولا recursive=false كإمضاء للدالة listFolders لأنها لن تقبل مثل هذه المعاملات الافتراضية/الاختيارية، وسينتج عن ذلك خطأ عند التجميع (compile error). لماذا؟ يرى مؤسسوا اللغة أن هذه السلوكيات تساهم في بناء واجهات برمجية (API) غير ثابتة أو تساهم في جعل تصرفها غير مُتوقع. في مثالنا السابق مثلا، هم يفضلون كتابة الدالة من دون معاملات افتراضية، أي: func listFolders(path string, subfolders bool, recursive bool) { ... }يجبرك هذا على كتابة التصرف الذي تريده من الدالة بشكل صريح عوض ترك الواجهة البرمجية تملي عليك التصرف الافتراضي، هذا لتقليل الأخطاء البشرية. أيضا قد يدفعك هذا إلى كتابة ثلاث دوال، كل بتصرفها الخاص الواضح من اسمها، مثال: listFolders, listFoldersRecursivly و listFoldersWithFirstLevelSubFolders. 4. لا توجد ميزة إثقال الدوال (Method Overloading)لنفس الأسباب السابقة، فإنه لا يوجد Method overloading، أي لا يمكنك إعادة تعريف دالة تحمل نفس الاسم لكن بإمضاء مغاير. مثلا، إذا وُجدت دالة باسم: func listFolders(path string) { ... }فلا يمكنك إنشاء دالة أخرى بنفس الاسم لكن بإمضاء مغاير مثل: func listFolder(path string, level int) { ... }بل عليك تغيير اسمها إلى مثلا: dunc listFolderToLevel(path string, level int) { ... }على الرغم من ذلك فهناك طريقة غير مباشرة لجعل دالة ما تقبل قيما اعتباطية عبر جعل الإمضاء من نوع {}interface سنتطرق إليها في الدروس القادمة. 5. لا وجود للعموميات (generics)تمكّنك باقي اللغات من كتابة دوال أو أصناف عامة، حيث لا تصرّح عند كتابتها بنوع المعاملات التي تقبلها لكن تترك لها مهمة معرفة نوع المعاملات لاحقا عند استدعائها، لعل أقرب مثال هو ما توفره لغة Java مثلا في صنف <List<T حيث T يرمز إلى أي نوع يتم تحديده لاحقا، بالتالي يمكن إنشاء <List<String أو <List<Integer بكل سهولة مع الحفاظ على نفس الوظائف والعمليات التي يمكن إجراؤها على القائمة List بشكل عام. لا يوجد في Go مثل هذا، وعوضا عن ذلك فهناك {}interface كنوع شامل يرضي جميع الأنواع، لكنه ليس كبديل تام لـ Generics. لماذا؟ سبب عدم توفر العموميات (Generics) في Go هو أن مؤسسيها لم يتبيّنوا بعد الطريقة الأنسب لهم لإضافة هذه الميزة إلى اللغة دون زيادة حِمل أثناء وقت التشغيل (run-time). 6. Go لُغة مملة كما أنها ليست أفضل لغة برمجة!لشدة بساطة اللغة وعدم إتيانها بشيء جديد، فإن الكثيرين يعتبرها لغة مملة. فعدد الكلمات المفتاحية بها والأنواع الأصلية فيها ضئيل مقارنة بباقي اللغات، كما أنها تقلل كثيرا من وجود أكثر من طريقة للقيام بمهمة معينة. حتى أنها لا تحتوي على حلقة while وتقتصر فقط على حلقة for، الكثيرون يعتبرون هذا من مزايا اللغة، لكني ذكرتها لك حتى لا تتوقع شيئا جديدا يصلح للتباهي. أيضا لن تسمح لك اللغة بترك متغير دون استعمال أو استيراد شيء غير مستعمل (unused import/variable) ولن يقبل المُجمع (compiler) أبدا بذلك. 7. لغة عنيدةمؤسسوا اللغة متشبثون برأيهم وقراراتهم في تصميم اللغة، فلا تتوقع تغيرات جوهرية قد تحدث على المدى القريب أو المتوسط في اللغة أو تغيرات في طريقة القيام بالأمور وسلوك المُجمّع (compiler). ولا داعي لفتح نقاشات فارغة حول تصميم اللغة وعيوبها إلا إذا كنت في نفس مستوى خبرتهم وحكمتهم. هم نفسهم يصرحون بهذا، ويذكرون أن هناك خيارات ولغات برمجة أخرى إن لم تعجبك Go. 8. لا يوجد إجماع على مدير حزم واحدتملك بايثون pip، وجافاسكريب تملك npm، وغيرهم من اللغات تملك مدير حزم (package manager) شهير أو متفق عليه، لا تخلو Go من مدير حزم، فهي تملك الكثير من ذلك، لكنها لم تتفق بعد على مدير حزم واحد ولا عن كيفية جلب وسرد الاعتماديات بطريقة قياسية، لكن حديثا يتم العمل على ذلك عبر مفهوم Vendoring. هذه الأمور الثمانية، للذكر وليس للحصر من أشد الانتقادات التي توجّه إلى Go كلغة برمجة، فإن كنت توافقها فقد لا تناسبك اللغة، وإن كنت ترى أن من ورائها حكمة -مثلي- فأكمل قراءة المقال حول أمور قد تعجبك حول Go. أشياء قد تحبها حول لغة البرمجة Go1. خيوط المعالجة المتوازية الخفيفة (goroutines)تسمح لك Go بعمل معالجة متوازية والاستفادة من كامل قوة المعالج (CPU) لديك بكل بساطة، حيث تملك ما يسمى بـ goroutine وهو خيط معالجة متوازي أخف من thread في باقي اللغات. يسمح لك هذا بإطلاق عشرات الآلاف من خيوط المعالجة المتوازية (عوض مثلا عشرات أو مئات threads فقط) دون عناء إنشائها وجعلها تتواصل فيما بينها أو تُكمّل بعضها البعض. يكفي مثلا لعمل دالة تعمل في خيط معالجة لوحدها بسبقها بالكلمة المفتاحية go، مثلا: go func(){ // دالة نكرة تقوم بعمل أمور في خيط معالجة لوحدها .... }هذا يسمح بكتابة تطبيقات عالية الأداء بشكل أسهل بكثير. 2. لغة تجميعية سريعة (compiled)عكس Ruby, Python, Java و PHP فإن Go لغة تجميعية، حيث أن الناتج النهائي لبرنامجك سيكون عبارة عن ملف تنفيذي قائم بذاته يحوي جميع الاعتماديات اللازمة لتشغيله دون الحاجة لاعتماديات خارجية، هذا مفيد جدا في تطوير الويب مثلا للتخلص أو تقليص مشاكل الاعتمادية (dependency hell). أيضا تساهم هذه الميزة في تسهيل عملية نشر التطبيق الخاص بك (deployment) حيث سيكون عليك فقط نقل الملف التنفيذي إلى الخادوم مثلا ثم تشغيله وكفى. لا حاجة لتنصيب أي شيء آخر لتشغيل برمجيتك، لا حاجة حتى لتنصيب Go على الخادوم نفسه. قد يتبادر إلى الذهن أن عملية التجميع (compiling) قد تأخذ وقتا خاصة إذا كان حجم البرنامج كبيرا، لكن الحقيقة أن عملية تجميع Go سريعة جدا وفي كثير من الأحيان لن تلاحظها حتى. 3. لغة إنتاجيةبسبب أنها لغة مملة، فإنها تضيق عليك مجال المجادلة مع زميلك في العمل أو من يعمل معك على المشروع أو البحث عن أفضل طريقة -مذهلة- للقيام بشيء ما، فكل شيء واضح وبسيط. 4. متعددة المنصات بامتيازنفس البرنامج يمكن إعادة تجميعه ليعمل على ويندوز، لينكس، Mac OSx أو حتى الهواتف الذكية ومعمارية ARM. حتى أنه بعد الإصدارة رقم 1.5 من Go يمكن إنشاء ملف تنفيذي لجميع المنصات من خلال المنصة التي أنت فيها، مثلا يمكن من خلال نظام لينكس إنشاء ملف تنفيذي لنظام ويندوز و Mac OS دون الحاجة ﻷن تكون على ذلك النظام. 5. مكتبة قياسية قوية (Rich Standard Library)على الرغم من حداثة اللغة، فإن مكتبتها القياسية حققت تقدما في ظرف قياسي. وغالبا ما يُنصح بالاعتماد على المكتبة القياسية قدر الإمكان، حيث تحتوي على أمور كثيرة تحتاجها أغلب أنواع التطبيقات، حتى أنها تحتوي على محرك قوالب html، أدوات للتعامل مع ترميز json، تشفير كلمات المرور وغيرها من الأمور الصالحة للاستعمال في تطبيقات الويب على سبيل المثال. 6. كل شيء Unicode افتراضاموضوع ترميز السلاسل النصية وكيفية التعامل مع الحرف رقميا كبير، لكن Go جعلت كل شيء unicode بشكل افتراضي إلا إذا تم تعيين غير ذلك صراحة. تملك Go نوع rune عوض نوع char في باقي اللغات، وهو ببساطة اختصار (alias) لنوع int32 فقط يشير إلى نقطة ترميز Unicode لذلك الحرف. بالتي فإن string في Go عبارة عن سلسلة rune وليس عن سلسلة char يشير إلى byte كما في C مثلا. 7. أدوات مساعدة جيدة مضمنة يمكن توليد توثيق برمجيتك بمجرد كتابة أمر godoc أو تحسين التنسيق بكتابة gofmt أو بدء إجراءات فحص الشفرة البرمجية (Unit testing مثلا) عبر كتابة go test وكلها أدوات تأتي مع تنصيب Go. 8. لغة سهلة من حيث الكتابة والتنسيق (Syntax)تنسيق اللغة شبيه نوعا ما بلغة بايثون، حيث لا وجود للفاصلة المنقوطة بعد نهاية كل تعليمة (;)، كما يمكن عمل متغير جديد دون تحديد نوعه، على الرغم من أن اللغة شديدة النوعية strongly styped إلا أنها توحي أنها سَلِسَة وديناميكية، مثلا يمكن كتابة age := 35 وسيتم اسناد نوع int إلى المتغير age. كما أنه يمكن للدوال إرجاع أكثر من قيمة كما في بايثون مثلا. لعل أكثر شيء مغاير لباقي اللغات هو طريقة كتابة الدوال، حيث أن القيمة التي تُرجعها الدالة تُكتب على يمين الدالة (كما في Pascal) وليس على يسارها، مثلا: func HelloHsoub() string { return "Hello Hsoub Academy!" }لاحظ أنه تم كتابة string على يمين الدالة وليس يسارها، أي أن هذه الدالة تُرجع قيمة من نوع string. يمكن للدوال إرجاع دوال أخرى أيضا كقيمة كما يمكن للمتغيرات أن تشير إلى دوال (كما في جافاسكريبت وبايثون...) مثلا: sayHi := HelloHsoub حتى لا أنحاز، فهذه 8 أشياء قد تحبها سأتوقف عندها مقابل 8 قد لا تعجبك كنت قد ذكرتها. بهذا نكون وصلنا إلى ختام الدرس الأول -الكلامي- من هذه السلسلة، والتي رأيت أن أبدأها هكذا عمدا ولو أن بعضا مما قيل في هذا الدرس قد لا يكون بالضرورة موجها للمبرمج المبتدئ، لكني سأحاول جعل الدروس القادمة أبسط ما يكون وتُعنى بالمبتدئ أولا.
  6. بعد تعرُّفنا في الدرس السابق على لغة Go ونقاط اختلافها مع باقي لغات البرمجة، سنحاول في هذا الدرس شرح كيفية تنصيبها، تهيئة وفهم بيئة العمل (Workspace) الخاصة بها. من المهم جدا فهم تقسيم المجلدات الذي تمليه عليك بيئة عمل Go، حيث سيمكّنك ذلك من ترتيب مشروعك بشكل أفضل، تسهيل مشاركته، وجعله قابلا للجلب والتضمين في مشاريع أخرى عبر أمر go get الذي سنتعرّف عليه لاحقا. تملك Go نوعين من المُجمّعات (Compilers). وكتذكير سريع، وظيفة المُجمّع هي أخذ شيفرتك البرمجية في شكلها النصّي البحت، وتحويلها إلى برنامج تنفيذي (أو مكتبة). أحد مجمّعَيْ Go هو المجمع القياسي الذي يحمل اسم gc اختصارًا لـ Go Compiler، والآخر مُجمّع يعتمد على مجمّع gcc وما يوفره كمنصة ودعم معماريات معالجات (CPU) أكثر ويحمل اسم gccgo. يجدر الإشارة إلى أن مجمع gccgo متأخر نوعا ما في زرع كامل مواصفات النسخة الأحدث من Go، فعلى سبيل المثال، ولدى كتابة هذا الدرس، يوفر gccgo نسخة 1.4.1 من Go في حين يوفر gc دائما آخر نسخة (1.5.2) من اللغة. ذكرت هذا من باب العلم بالشيء، وباختصار، إن لم يهمك دعم معماريات أكثر أو بعض تفاصيل منصة gcc فلن تحتاج إلى gccgo وستكتفي بـ gc القياسي وهو ما سنتبعه خلال هذه السلسلة. تنصيب Goكما ذكرنا في الدرس السابق، فإن Go لغة متعددة المنصّات بامتياز، وهي جاهزة للتحميل والتنصيب على نظامك المفضل لكلا معماريتي 32bit و 64bit. تنصيب Go على Windows و Mac OSيكفي التوجه إلى موقع اللغة ثم تحميل النسخة الخاصة بنظامك. عملية تنصيبها عادية وهي مشابهة لعملية تنصيب أي برنامج عادي آخر. بعد التنصيب، تأكد من أن العملية تمت بنجاح عبر كتابة go version أو فقط go في سطر الأوامر. إن كنت على Windows تأكد من غلق أي نافذة سطر أوامر مفتوحة مسبقا (إن وُجدت) ثم فتح نافذة جديدة. تنصيب Go على Linuxأنصحك بالاطلاع على مدير حزم توزيعتك قبل تحميل وتنصيب Go من أي مكان آخر. فإن وجدت أن مدير حزم توزيعتك يوفر آخر نسخة من Go فسيكون الأمر أسهل بكثير، إن وجدت أن توزيعتك توفر نسخة أقدم من Go 1.5.1 فعليك تنصيب آخر نسخة منها إن كنت تريد متابعة هذه السلسلة. إن كنت على Ubuntu والتوزيعات المبنية عليها، فأغلب الظن أن نسخة Go التي يوفرها مدير الحزم apt قديمة، كون التوزيعة يتم تحديثها كل 6 أشهر أو عامين (في حال كانت LTS). لذلك أنصحك بالتنصيب من خلال إضافة مستودع etherneum. sudo add-apt-repository -y ppa:ethereum/ethereum sudo apt-get update sudo apt-get install golangيُفترض بباقي التوزيعات أن تحتوي على آخر نسخة من Go، يكفي حينئذ التنصيب من مدير الحزم، مثلا على Arch Linux: sudo pacman -S goبعد التنصيب، تأكد من أن عملية التنصيب تمت بنجاح عبر كتابة go version أو فقط go في سطر الأوامر. من المفروض تتلقى نتيجة مشابهة لهذه: go version go1.5.2 linux/amd64فهم بيئة العملنقصد ببيئة العمل هنا أمران أساسيان: مجلد على حاسوبك، تقوم بإنشائه في أي مكان تريد، سيكون مكانا لجميع مشاريع Go.متغير بيئة (environment variable) يحمل اسم GOPATH يشير إلى هذ المجلد.لنفرض أنك سمّيت مجلد العمل باسم work، فإن هذا الأخير بدوره يجدر به أن يحوي ثلاث مجلدات فرعية أخرى: مجلد فرعي باسم src، حيث ستضع فيه جميع الشيفرات البرمجية لكامل مشاريع Go خاصتك.مجلد فرعي باسم bin، حيث سيقوم مجمع gc بنقل الملفات التنفيذية الناتجة عن شيفراتك البرمجية مباشرة إلى هذا المجلد.مجلد فرعي باسم pkg، مثل bin لكن ليس للملفات التنفيذية، إن كتبت برنامجا عبارة عن مكتبة وليس برنامجا تنفيذيا في حد ذاته، أو جلبت مكتبة خارجية عبر أمر go get، فسيتم تجميعها كمكتبة يتم وضعها في هذا المجلد حتى يسهل جلبها في باقي البرامج دون إعادة تجميعها في كل مرة (هذا يُسرّع من عملية تجميع برنامجك التنفيذي الذي يستخدم هذه المكتبات).باعتبار ما سبق، فإن بيئة Go ستكون مشابهة لهذا التقسيم الشجري: work # مجلد العمل ├── bin # مجلد الملفات التنفيذية الناتجة ├── pkg # مجلد المكتبات البرمجية الناتجة └── src # مجلد شيفراتنا البرمجية هل هذا كل شيء؟ طبعا لا. بما أن Go لغة حديثة نسبيا، فإنها تفترض أنك ستستضيف شيفرتك البرمجية في مكان (مستودع) ما، وهذه عادة أي مبرمج محترف، خشية على الشيفرة البرمجية من الضياع أو من أجل مشاركتها مع أناس آخرين. طبعا مستودع شيفرتك البرمجية سيكون مُدارا بأحد أدوات إدارة النُسخ (VCS) مثل Git أو Mercurial مثلا. قد تكون الشيفرة على خادومك الخاص (Server)، أو على أحد خدمات استضافة المشاريع البرمجية مثل Github و Bitbucket. بما أن Github أشهر المنصات لمشاركة الشيفرات البرمجية، فسأضرب به المثال. تدفعك Go (أي أنه من المستحسن) إلى وضع شيفرتك البرمجية في مسار مشابه لمسار حسابك على github مثلا -وحتى أقرّب الصورة- لنفرض أن حسابك على github اسمه HsoubAcademy وبالتالي رابط حسابك هو: https://github.com/HsoubAcademyإذا أنشأت مشروعا بـ Go يحمل اسم example على سبيل المثال ثم رفعته على Github باستخدام حسابك HsoubAcademy فسيكون رابط المشروع هو: https://github.com/HsoubAcademy/exampleبالتالي فإن Go تدفعك ﻷن يكون مجلد المشروع على حاسوبك مشابها لهذا الرابط، أي تحت هذا المسار: work/src/github.com/HsoubAcademy/exampleحيث: github.com هو مجلد فرعي تحت مجلد src.HsoubAcademy هو مجلد فرعي تحت مجلد github.com آنف الذكر، غيّره إلى حسابك على Github مثلا.example هو مجلد فرعي يحوي ملفات مشروعك تحت مجلد HsoubAcademy.ملاحظة: أسماء المجلدات حسّاسة لحالة الأحرف (case-sensitive) ماعدا على نظام Windows. لماذا ترتيب بيئة العمل بهذا الشكل؟ببساطة ﻷن التنظيم بهذا الشكل مفيد جدًا من ناحيتين: 1. بالإمكان جلب أي مكتبة خارجية بمجرد عمل import لها من مسار مستودعها، مثلا: لنفرض أننا نريد استعمال مكتبة لنزع التشكيل عن النص العربي، سنستخدم مكتبة goarabic، سيكفي لتضمينها في مشروعنا البرمجي كتابة الأمر: go get github.com/01walid/goarabic2. يقوم أمر go get بوضع ناتج تجميع هذه المكتبة في مجلد pkg بنفس مسار رابطها على github، أي سيضعها داخل مجلد فرعي باسم 01walid داخل مجلد github.com الذي هو بدوره عبارة عن مجلد فرعي داخل مجلد العمل، بالتالي يمكن تضمينها مباشرة في مشروعنا بهذا الشكل: import "github.com/01walid/goarabic" لاحظ أن مسار استيراد هذه المكتبة هو نفسه رابطها على github. هذا يُسهّل من عملية مشاركة المكتبات البرمجية وإثراء مكتبات اللغة نفسها. من المهم جدا أن يتبع مشروعك نفس هذا المنهاج، خاصة إن كان عبارة عن مكتبة. تهيئة بيئة العملإن كنت على لينكس أو Mac OS، يمكنك مثلا إنشاء مجلد باسم work داخل مجلد Home خاصتك بكتابة أمر: mkdir $HOME/workثم جعل هذا الأخير هو بيئة عمل Go عبر إنشاء متغير بيئة باسم GOPATH (حسّاس لحالة الأحرف) يُشير له: export GOPATH=$HOME/workطبعا لجعل هذا المتغير دائم حتى بعد إعادة التشغيل، سيكون عليك كتابته في bashrc. (في حال كنت تستعمل صدفة bash، أو ملف zshrc. إن كنت تستعمل صدفة zsh كمثال، وهي ملفات موجود داخل مجلد المنزل خاصتك HOME$). أما إن كنت على Windows فيكفي إضافة متغير باسم GOPATH عبر التوجه إلى: خصائص النظام (System -> Advanced system settings)ثم النقر على متغيرات البيئة (Environment Variables)ثم إضافة المتغير من قسم System variables كما هو مبين أسفله. إذا كان مجلد عملك مثلا في Windows هو C:\Projects\Go فسيكون عليك إضافته بهذا الشكل: يمكنك التحقق من أنه تم إضافة المتغير الجديد، عبر فتح نافذة سطر أوامر جديدة، وكتابة الأمر: %echo %GOPATH كما هو موضح أسفله: إن تم إظهار المسار المُختار لمجلد عملك، فقد قمت أخيرًا بتنصيب Go وتهيئتها بنجاح. إضافة (Bonus)ماذا لو أمكننا جعل البرامج التنفيذية التي نكتبها أو نجلبها عبر أمر go get متوفرة مباشرة لدينا في نافذة سطر الأوامر دون التصفح إليها في كل مرة؟ مثلا لنقل أننا نريد الاستفادة من أداة ha المكتوبة بلغة Go، لتحويل ملفات Markdown إلى HTML جاهز للّصق على محرر آخر، نقوم بجلب الأداة: go get github.com/HsoubAcademy/haبما أن أداة ha عبارة عن برنامج تنفيذي فإن أمر go get سينقله مباشرة إلى مجلد bin داخل بيئة العمل. لكن لا نريد التنقل إلى مجلد bin داخل مجلد العمل لاستعمالها، نريد فقط كتابة ha في سطر الأوامر مباشرة للاستفادة من الأداة واستعمالها حتى وإن كنا في مجلد آحر. بما أن Go تقوم بوضع ناتج الملفات التنفيذية في مجلد bin تحت مجلد العمل، بالتالي، يكفي إضافة مسار مجلد bin إلى مسارات متغير البيئة PATH ليكون كل شيء متوفر لديك! حتى برامجك التنفيذية التي تكتبها بنفسك. بالنسبة لمستخدي Linux أو Mac OS فإن ذلك ممكن عبر إضافة مسار مجلد bin داخل مجلد العمل إلى متغير البيئة PATH: export PATH=$PATH:$GOPATH/binأما لمستخدمي Windows فعليهم إضافة مسار مجلد bin داخل مجلد العمل إلى متغير البيئة PATH عبر التوجه إلى: خصائص النظام (System -> Advanced system settings)ثم النقر على متغيرات البيئة (Environment Variables)البحث عن قيمة Path في قسم System variables ثم الضغط على edit وإضافة المسار إلى آخر السطة مسبوقا بفاصلة منقوطة (;) كما هو مبين أسفله. الآن ستجد أن كل ما هو موجود في مجلد bin من برامج وأدوات متاح لك، من ذلك أداة ha التي أشرنا إليها سابقا (جرب فتح نافذة سطر أوامر جديدة وكتابة الأمر ha). بهذا نأتي إلى نهاية الدرس الثاني من هذه السلسلة، سنشرع في الدرس القادم في كيفية بدء البرمجة بـ Go والاستفادة من بيئة العمل هذه.