الأساسيات

الحزم Packages

  • ماهي الحزم Packages في لغة غو Go ؟

حتى الان, في الدروس والأمثلة السابقة عن لغة غو, كانت دائماً برامجنا مؤلفة من ملف واحد بهدف تبسيط شرح المبادئ والاساسيات, ولكن في الحياة العملية والبرامج الفعلية عادةً ماتكون هذه البرامج
مؤلفة من عدة ملفات برمجية, حيث أنه من شبه المستحيل ان يتسع برنامج ضخم في ملف برمجي واحد لأنه عندها سيصعب جداً التعديل عليه وتصحيح أخطاءه وماشابه ذلك
ومن هنا تأتي أهمية استخدام الحزم في لغة غو !

الحزم في لغة غو تٌستخدم لتنظيم وترتيب الأكواد وملفات .go البرمجية لتحسين وتبسيط عملية البرمجة وتصحيح الأخطاء وإضافة التعديلات على برامجنا
ونظام الحزم في لغة غو ليس جديد أو غريب, فنرى لغات برمجية اخرى تستخدم هذا النظام مثل لغة بايثون Python ولغة سي شارب C# وغيرهما الكثير ..

 

  • دالة main وحزمة main

    كل برنامج يُكتب بلغة غو يجب أن يحتوي على دالة main وهي تعتبر بمثابة نقطة الدخول entry-point بالنسبة للبرنامج, فمنها يبدأ عمل البرنامج كما في لغات عديدة مثل سي بلس بلس C++ وغيرها
    ودالة main يجب أن تكون ضمن حزمة main

ولكي ننسب ملف برمجي ما الى حزمة ما, نستخدم التصريح الاتي في بداية الملف

package packagename

وهو أول سطر برمجي يُكتب في بداية كل ملف برمجي .go

إذاً لنبدأ بإنشاء دالة main و حزمة main لبرنامجنا …

1- أنشئ مجلد جديد داخل مجلد src وسمّه ماتريد حسب مشروعك, وليكن مثلاً geometry
2- أنشئ ملف جديد باسم geometry.go داخل مجلد geometry
3- افتح ملف geometry.go واكتب فيه الكود التالي:

package main

import "fmt"

func main() {
fmt.Println("Geometrical shape properties")
}

نلاحظ أن أول سطر هو package main , وهو يحدد أن هذا الملف يتبع للحزمة main

ونلاحظ تعليمة استدعاء الحزم import , حيث من خلالها نستطيع استدعاء حزم اخرى لنستخدمها في برنامجنا,
وفي حالتنا هذه قمنا باستدعاء الحزمة fmt وهي تعني (Format) أي تنسيق, وهي حزمة أساسية قياسية تأتي مع لغة غو بشكل تلقائي, ومن خلالها نستطيع عرض النصوص وتنسيقها و..الخ
وداخل حزمة fmt القياسية يوجد دالة تٌدعى Println اختصاراً لـ (Print Line) حيث تقوم هذه الدالة بالكتابة على سطر جديد, ومن خلالها قمنا بكتابة عبارة “Geometrical shape properties”.

4- نقوم بعمل تجميع Compile للبرنامج عبر الأمر التالي

go install geometry

وهذا الأمر يقوم بالبحث عن الملف الذي يحتوي على الدالة main داخل مجلد geometry, وفي حالتنا هذه سيجد الملف geometry.go وسيقوم بعملية تجميعه وإنشاء ملف تنفيذي Executable Binary
وسيضعه في مجلد bin المناظر لمجلد src

ملاحظة: في بعض الحالات قد يتم انشاء الملف التنفيذي داخل مجلد src وذلك يعود لوجود أخطاء في تعيين متغيرات البيئة Enviroment Variables الخاصة بلغة غو مثل GOPATH و GOBIN

ملاحظة: أيضاً في بعض الحالات قد لايكون الملف التنفيذي قابل للتشغيل وسبب ذلك أيضاً يعود لسوء ضبط متغيرات البيئة الخاصة بلغة غو, وخاصة المتغير GOOS والمتغير GOARCH

انتقل الان عبر محرر الأوامر الى مجلد bin وشغّل الملف التنفيذي geometry
وانظر الى النتيجة …

  • انشاء حزمة جديد Custom Package

في الأمثلة السابقة استخدمنا حزم قياسية Standard Packages تأتي بشكل افتراضي مع لغو غو ..
أما الان سننشئ حزمة خاصة بنا حيث ستحتوي على بعض وظائف المستطيلات ومايتعلق بها, وسنسمي الحزمة rectangle

هام: في لغة غو, الحزم يجب أن توضع في مجلد خاص بها, ويجب أن يكون اسم المجلد بنفس اسم الحزمة.

نعود الان لمجلد geometry , ولننشئ بداخله مجلد جديد ونسمّه rectangle
ويجب الانتباه هنا الى أن جميع الملفات البرمجية التي سننشئها يجب أن تتبع للحزمة rectangle وذلك نحدده بواسطة السطر الأول من كل ملف (اذا كانت الحزمة تحتوي عدة ملفات)

package rectangle

لننشئ الان ملف باسم rectprops.go داخل مجلد rectangle ونكتب فيه الكود التالي

package rectangle

import "math"

func Area(len, width float64) float64 {
area := len * width
return area
}

func Diagonal(len, width float64) float64 {
diagonal := math.Sqrt((len * len) + width * width))
return diagonal
}

في الكود أعلاه, في السطر الأول قمنا بتحديد تبعية الملف الى الحزمة rectangle
وقمنا باستيراد المكتبة القياسية المسماة math حيث أنها تساعدنا في العمليات الحسابية
ومن ثم أنشئنا دالتين, دالة Area لحساب مساحة المستطيل, ودالة Diagonal لحساب قطر المستطيل
ونلاحظ أنه داخل دالة حساب قطر المستطيل, قمنا باستخدام الدالة Sqrt التابعة للحزمة القياسية math, ومهمة هذه الدالة هي حساب الجذر التربيعي

ملاحظة: بدأنا تسمية دالتي Area وDiagonal بأحرف كبيرة, ولهذا الأمر دلالة خاصة بلغة غو, حيث أن اذا كان اسم الدالة يبدأ بحرف كبير فهي تعتبر public وان كان بحرف صغير فهي تعتبر private, وسيتم شرح هذا الامر بالتفصيل لاحقاً.

  • استيراد الحزم Importing Custom Packages

لاستيراد/استخدام الحزم نستخدم التعليمة import ومن ثم “اسم الحزمة” بين علامتي اقتباس مضاعفتين Double-quotes
ويجب أن نشير الى مسار الحزمة المراد استيرادها من وجهة نظر مجلد المسار GOPATH
فنجد أن حزمتنا تقع في المسار geometry/rectangle

ولكننا قد نحتاج أيضاً استخدام المكتبة القياسية fmt لعرض النتائج
ويمكننا استيراد عدة حزم من خلال أمر import واحد عبر الصيغة التالية

import (
"fmt"
"geometry/rectangle"
)

نعود الان للملف geometry.go ونكتب فيه الاتي من جديد ..

package main

import (
"fmt"
"geometry/rectangle"
)

func main() {
var rectLen, rectWidth float64 = 6, 7
fmt.Println("Geometrical shape properties")

fmt.Printf("area of rectangle %.2f\n", rectangle.Area(rectLen, rectWidth))

fmt.Printf("diagonal of the rectangle %.2f ",rectangle.Diagonal(rectLen, rectWidth))
}

ونقوم بحفظه وتجميعه Compile وتشغيله لنرى النتيجة التالية ..

Geometrical shape properties
area of rectangle 42.00
diagonal of the rectangle 9.22
  • مفهوم “الأسماء” المصدّرة Exported Names

في اغلب اللغات البرمجية الاخرى, يتم استخدام الكلمات المفتاحية مثل public وprivate وprotected وذلك لتحديد نطاق عمل الدوال والمتغيرات
في لغة غو نستخدم طريقة اخرى وهي الأسماء المصدّرة
حيث أن اسم الدالة ذا كان يبدأ بحرف كبير Capitalised , إذاً فهذه الدالة يُمكن استخدامها في عدة ملفات برمجية اخرى اذا تم استيراد المكتبات التابعة لها (كما في مثالنا السابق حيث أن الدالة Area كانت بملف rectProps.go وقمنا باستخدامها في ملف geometry.go)
أما اذا كان اسم الدالة يبدأ بحرف صغير, فهذا يعني أن هذه الدالة لايمكن استدعاؤها او استخدامها إلا داخل الملف الذي كُتبت فيه
وحسبنا أن ننظر الى كافة الدروس السابقة حيث استخدمنا الدالة Println التي استدعيناها من حزمة fmt, نلاحظ أنه في كل المرات كنا نكتب اسم الدالة بحرف كبير وليس حرف صغير !

ويمكنك تجربة مثلاً ان تستبدل الحرف الكبير الأول بدالة Area (الموجودة في ملف rectprops.go), أن تستبدله بحرف صغير وأن تعيد تجميع البرنامج
سترى رسالة خطأ مشابهة للاتي ..

geometry.go:11: cannot refer to unexported name rectangle.area

الخلاصة, إذا أردت استدعاء دالة من مكتبة ما, يجب أن يكون اسم الدالة في المكتبة يبدأ بحرف كبير .

  • دالة init في الحزم

هي دالة يُمكن أن تكون في أي حزمة, وهي شبيهة بالـ Constructor في لغات البرمجة الاخرى

ومن قواعد استخدامها,
ألا يكون لها أية باراميترز Parameters
ألا تُرجع أية قيم Return values
ألا تٌستدعى بشكل مباشر Explicit

وتُكتب بالصيغة التالية

func init() {
}

تٌستخدم دالة init لتقوم بالتحضير لبدأ عمل الحزمة Initialization, فمثلاً أن تتأكد من صحة القيم المدخلة أو إسناد قيم لبعض المتغيرات ومهام اخرى, قبل أن يبدأ التنفيذ .

حيث أنه عند استدعاء مكتبة, أولاً يتم تعيين قيم المتغيرات ومن ثم مباشرة يبدأ عمل دالة init (إن وُجدت), وقد تحتوي الحزمة على عدة دوال init في ملف واحد أو موزعة في عدة ملفات.

لنقوم الان ببعض التغييرات على برنامجنا السابق لنرى كيفية استخدام دالة init

نبدأ بإضافة دالة init في rectprops.go

package rectangle

import "math"
import "fmt"

/*
* init function added
*/
func init() {
fmt.Println("rectangle package initialized")
}
func Area(len, wid float64) float64 {
area := len * wid
return area
}

func Diagonal(len, wid float64) float64 {
diagonal := math.Sqrt((len * len) + (wid * wid))
return diagonal
}

قمنا بإضافة دالة init حيث تطبع جملة “rectangle package initialised” فقط

والان لنعدل الحزمة main, نعلم مسبقاً أن طول وعرض المستطيل يجب أن يكونا أكبر من صفر, سنقوم بإضافة طريقة للتحقق من هاتين القيمتان باستخدام دالة init, وسنعيّن دالتي الطول والعرض ليكونا على مستوى الحزمة main بأكملها وليس فقط دالة main كما في السابق.

لنعدل الان ملف geometry.go

package main

import (
"fmt"
"geometry/rectangle" //importing custom package
"log"
)
/*
* 1. package variables
*/
var rectLen, rectWidth float64 = 6, 7

/*
*2. init function to check if length and width are greater than zero
*/
func init() {
println("main package initialized")
if rectLen 

قمنا بتعديلان..
الأول.. غيرنا مكان المتغيران rectLen و rectWidth من دالة main إلى خارجها, أي أصبح المتغيران على مستوى الحزمة package-level ككل وليس فقط الدالة main.
الثاني.. بدالة init قمنا بإضافة تحقق اذا قيمة طول المستطيل او عرضه تساويان صفر, فسيتم إيقاف تنفيذ البرنامج وعرض رسالة خطأ وذلك باستخدام الدالة log.Fatal

الان عند تنفيذ البرنامج سنلاحظ أن النتيجة ستكون كالاتي

rectangle package initialized
main package initialized
Geometrical shape properties
area of rectangle 42.00
diagonal of the rectangle 9.22

وهذا يعني أن لغة غو, أولاً تم استيراد الحزم من import وتم تشغيل دوال الـinit الخاصة بكل حزمة
وثانياً, تم تعيين قيم المتغيران rectLen وrectWidth
وثالثاً, تم استدعاء الدالة init الخاصة بالملف نفسه
ورابعاً, تم استدعاء الدالة main

وللترتيب هنا أهمية كبيرة.

في لغة غو, من غير القانوني أن تستدعي حزمة دون أن تستخدمها في مكان ما في برنامجك, وسبب ذلك هو للتقليل من الأكواد المبعثرة غير المفيدة وبالتالي ذلك سيفيدنا في سرعة تجميع البرنامج Compilation-time

ملاحظة: يمكنك تشغيل أكواد وأمثلة لغة غو من خلال GoLang Playground أو GoPlay.Space .

نبذة عن الكاتب

Firas M. Darwish

Software Engineer, PHP/Laravel, C#, GoLang, founder of ArGoLang.com & others ..

شاركنا رأيك :)