القواعد الأساسية
القواعد الأساسية لـ Go بسيطة وسهلة الفهم، دعنا نبدأ بمثال بسيط.
package main
import "fmt"
func main() {
fmt.Println("Hello 世界!")
}الكلمة المفتاحية
packageتعلن الحزمة التي ينتمي إليها ملف go الحالي، يجب أن يكون الملف الرئيسي معلناً كحزمةmain، والدالة الرئيسية هي دالةmain، ويجب تجنب تكرار هذه الأسماء عند تعريف حزم ودوال مخصصة.importهو كلمة مفتاحية للاستيراد، يليها اسم الحزمة المراد استيرادها.funcهو كلمة مفتاحية لتعريف الدوال، تُستخدم للإعلان عن دالة.fmt.Println("Hello 世界!")هو عبارة تستدعي دالةPrintlnمن حزمةfmtللإخراج.
هذا مقدمة بسيطة للقواعد، دعنا نتعرف بشكل أكثر تفصيلاً على هذه المفاهيم.
الحزم
في Go، تُبنى البرامج من خلال ربط الحزم معاً. الوحدة الأساسية للاستيراد في Go هي الحزمة، وليس ملف .go. الحزمة هي في الواقع مجلد، والاسم الإنجليزي هو package، وتمتلك الحزمة جميع المتغيرات والثوابت والأنواع المُعرَّفة مشتركة. يُنصح بأن تكون تسمية الحزم بأحرف صغيرة ومختصرة قدر الإمكان.
الرؤية
ذكرنا سابقاً أن جميع المتغيرات والثوابت والأنواع المُعرَّفة مشتركة داخل الحزمة، لكن بالنسبة للخارج الأمر مختلف، أحياناً لا تريد للآخرين الوصول إلى نوع معين، لذلك تحتاج للتحكم في الرؤية. ربما رأيت في لغات OOP أخرى كلمات مفتاحية مثل Public، Private، لكن في Go لا توجد هذه الكلمات، طريقة التحكم في الرؤية بسيطة جداً، والقواعد كالتالي:
- الاسم الذي يبدأ بحرف كبير هو نوع/متغير/ثابت عام
- الاسم الذي يبدأ بحرف صغير أو شرطة سفلية هو نوع/متغير/ثابت خاص
مثال: الثابت MyName عام، بينما الثابت mySalary خاص.
package example
// عام
const MyName = "jack"
// خاص
const mySalary = 20_000هذه القاعدة للرؤية تنطبق على جميع أنحاء لغة Go.
الاستيراد
استيراد حزمة لاستخدام الأنواع/الطرق/الدوال/المتغيرات فيها، صيغة الاستيراد هي import متبوعة باسم الحزمة:
package main
import "example"عند استيراد حزم متعددة، يمكنك كتابتها هكذا:
package main
import "example"
import "example1"أو يمكن وضعها بين قوسين، وهذه الطريقة أكثر شيوعاً في الممارسة:
package main
import (
"example"
"example1"
)إذا كان هناك تكرار في أسماء الحزم، أو كانت أسماء الحزم معقدة، يمكنك إعطاؤها أسماء مستعارة:
package main
import (
e "example"
e1 "example1"
)عندما يكون الاسم المستعار شرطة سفلية _ فهذا يسمى استيراد مجهول، الحزمة المستوردة بشكل مجهول لا يمكن استخدامها، هذا يُفعل عادةً لتحميل دالة init في الحزمة دون الحاجة لاستخدام أنواع الحزمة، مثال شائع هو تسجيل برنامج تشغيل قاعدة البيانات دون الحاجة لاستخدامه يدوياً.
package main
import (
e "example"
_ "mysql-driver-go"
)بعد الاستيراد، عندما تريد الوصول إلى نوع في الحزمة، استخدم اسم_الحزمة.المعرف، مثلاً:
package main
import (
"example"
"fmt"
)
func main() {
fmt.Println(example.MyName)
}هناك طريقة استيراد خاصة وهي استيراد جميع أنواع الحزمة إلى النطاق الحالي، الأنواع المستوردة بهذه الطريقة لا تحتاج لعامل . للوصول، لكن إذا كان هناك أنواع بنفس الاسم فلن يتم الترجمة.
package main
import (
. "example"
)WARNING

لا يمكن في Go الاستيراد الدائري، سواء بشكل مباشر أو غير مباشر. مثلاً الحزمة A تستورد الحزمة B، والحزمة B تستورد الحزمة A، هذا استيراد دائري مباشر. الحزمة A تستورد الحزمة C، والحزمة C تستورد الحزمة B، والحزمة B تستورد الحزمة A، هذا استيراد دائري غير مباشر. وجود استيراد دائري سيمنع الترجمة.
الحزمة الداخلية
في Go، هناك اتفاق أن حزمة باسم internal داخل حزمة ما هي حزمة داخلية، الحزم الخارجية لا يمكنها الوصول إلى أي محتوى في الحزمة الداخلية، وإلا فلن تتم الترجمة، دعنا نرى مثالاً:
/home/user/go/
src/
crash/
bang/ (go code in package bang)
b.go
foo/ (go code in package foo)
f.go
bar/ (go code in package bar)
x.go
internal/
baz/ (go code in package baz)
z.go
quux/ (go code in package main)
y.goمن هيكل الملفات، الحزمة crash لا يمكنها الوصول إلى أنواع الحزمة baz.
التعليقات
تدعم Go التعليقات أحادية السطر والتعليقات متعددة الأسطر، يُنصح بترك مسافة واحدة بين التعليق والمحتوى، مثلاً:
// هذه حزمة main
package main
// تم استيراد حزمة fmt
import "fmt"
/*
*
هذه دالة البدء main
*/
func main() {
// هذا عبارة
fmt.Println("Hello 世界!")
}المعرفات
المعرف هو اسم يُستخدم لتسمية الحزم والدوال والمتغيرات وما إلى ذلك، قواعد التسمية كالتالي:
- يجب أن يتكون من أحرف وأرقام وشرطات سفلية فقط
- يجب أن يبدأ بحرف أو شرطة سفلية فقط
- حساس لحالة الأحرف
- لا يمكن تكرار أي معرف موجود، أي يجب أن يكون فريداً في الحزمة
- لا يمكن أن يتعارض مع أي كلمة مفتاحية مدمجة في Go
فيما يلي جميع الكلمات المفتاحية المدمجة، يمكنك أيضاً زيارة دليل المرجع - المعرفات لمزيد من التفاصيل:
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return varالعوامل
فيما يلي ترتيب أولويات العوامل المدعومة في Go، يمكنك أيضاً زيارة دليل المرجع - العوامل لمزيد من التفاصيل:
Precedence Operator
5 * / % << >> & &^
4 + - | ^
3 == != < <= > >=
2 &&
1 ||شيء واحد يجب ملاحظته، Go لم تختر ~ كعامل للنفي، بل أعادت استخدام رمز ^، عندما يُستخدم ^ بين رقمين، مثل a^b، يكون عامل XOR، وعندما يُستخدم مع رقم واحد فقط، مثل ^a، يكون عامل النفي. تدعم Go أيضاً عوامل الإسناد المُحسَّنة، كالتالي:
a += 1
a /= 2
a &^= 2TIP
لا توجد في Go عوامل الزيادة والنقصان الذاتية، تم تخفيضها إلى عبارة statement، وتحديد أنها يجب أن تكون بعد المُعامل، لذا لا حاجة للقلق حول i++ و ++i.
a++ // صحيح
++a // خطأ
a-- // صحيحأيضاً، لم تعد لها قيمة مُرجعة، لذا كتابة a = b++ خاطئة.
القيم الحرفية
القيمة الحرفية، وفقاً لمصطلحات علوم الحاسوب، هي رمز يُعبِّر عن قيمة ثابتة في الكود المصدري، وتسمى أيضاً القيمة الحرفية. الاسمان يعنيان نفس الشيء، ما تكتبه يكون هو القيمة، أي القيمة "بالمعنى الحرفي".
القيم الحرفية الصحيحة
لتسهيل القراءة، يُسمح باستخدام الشرطة السفلية _ لتقسيم الأرقام، لكن يُسمح بها فقط بعد البادئة و بين الأرقام.
24 // 24
024 // 24
2_4 // 24
0_2_4 // 24
10_000 // 10k
100_000 // 100k
0O24 // 20
0b00 // 0
0x00 // 0
0x0_0 // 0القيم الحرفية للفاصلة العائمة
من خلال بادئات مختلفة يمكن التعبير عن أرقام فاصلة عائمة بأنظمة مختلفة:
0.
72.40
072.40 // == 72.40
2.71828
1.e+0
6.67428e-11
1E6
.25
.12345E+5
1_5. // == 15.0
0.15e+0_2 // == 15.0
0x1p-2 // == 0.25
0x2.p10 // == 2048.0
0x1.Fp+0 // == 1.9375
0X.8p-0 // == 0.5
0X_1FFFP-16 // == 0.1249847412109375
0x15e-2 // == 0x15e - 2 (integer subtraction)القيم الحرفية للأعداد المركبة
0i
0123i // == 123i
0o123i // == 0o123 * 1i == 83i
0xabci // == 0xabc * 1i == 2748i
0.i
2.71828i
1.e+0i
6.67428e-11i
1E6i
.25i
.12345E+5i
0x1p-2i // == 0x1p-2 * 1i == 0.25iالقيم الحرفية للحروف
يجب وضع القيم الحرفية للحروف بين علامتي اقتباس فردية ''، وحروف Go متوافقة تماماً مع utf8.
'a'
'ä'
'你'
'\t'
'\000'
'\007'
'\377'
'\x07'
'\xff'
'\u12e4'
'\U00101234'أحرف الهروب
أحرف الهروب المتاحة في Go:
\a U+0007 رمز الجرس
\b U+0008 رمز الرجوع
\f U+000C رمز تغذية الورقة
\n U+000A رمز السطر الجديد
\r U+000D رمز العودة
\t U+0009 رمز الجدولة الأفقية
\v U+000B رمز الجدولة العمودية
\\ U+005C هروب الشرطة المائلة العكسية
\' U+0027 هروب الاقتباس الفردي (صالح فقط داخل الحروف)
\" U+0022 هروب الاقتباس المزدوج (صالح فقط داخل السلاسل النصية)القيم الحرفية للسلاسل النصية
يجب وضع القيم الحرفية للسلاسل النصية بين علامتي اقتباس مزدوجتين "" أو بين علامتي اقتباس عكسيين `` (السلسلة النصية بعلامات الاقتباس العكسية لا تدعم الهروب):
`abc` // "abc"
`\n
\n` // "\\n\n\\n"
"\n"
"\"" // `"`
"Hello, world!\n"
"今天天气不错"
"日本語"
"\u65e5本\U00008a9e"
"\xff\u00FF"الدوال
طريقة تعريف الدوال في Go تتم من خلال الكلمة المفتاحية func، وهي مشابهة لمعظم اللغات:
func main() {
println(1)
}لكن دوال Go لها نقطتان مختلفتان، الأولى هي أن نوع المعامل يأتي بعد الاسم، هكذا:
func Hello(name string) {
fmt.Println(name)
}النقطة الثانية المختلفة هي القيم المُرجعة المتعددة، ويمكن أن تكون مُسمَّاة:
func Pos() () (x, y float64) {
...
}الأسلوب
بالنسبة لأسلوب البرمجة، تُلزم Go الجميع بنفس الأسلوب، توفر Go الرسمية أداة تنسيق gofmt، يمكن استخدامها من سطر الأوامر، هذه الأداة لا تقبل أي معاملات تنسيق، المعاملان الوحيدان فقط يُظهران عملية التنسيق، لذا لا تدعم التخصيص تماماً، أي أن جميع الأكواد التي تمر عبر هذه الأداة ستكون بنفس الأسلوب، وهذا يقلل بشكل كبير من العبء الذهني للمُشتغلين على الكود، لذا السعي للتميز في هذا الجانب ليس خياراً حكيماً.
فيما يلي بعض القواعد البسيطة، يمكن الانتباه لها أثناء كتابة الكود.
وضع الأقواس المعقوفة للدوال
حول ما إذا كان يجب وضع قوس معقوف جديد بعد الدالة، يمكن لكل مبرمج أن يقول رأيه، في Go جميع الأقواس المعقوفة يجب ألا توضع في سطر جديد:
// مثال صحيح
func main() {
fmt.Println("Hello 世界!")
}إذا فعلت ذلك فعلاً، هكذا:
// مثال خاطئ
func main()
{
fmt.Println("Hello 世界!")
}هذا الكود لن يتم ترجمته أصلاً، لذا تُلزم Go جميع المبرمجين بعدم وضع القوس المعقوف في سطر جديد.
المسافات البادئة
تستخدم Go افتراضياً Tab أي علامة الجدولة للمسافات البادئة، وتستخدم المسافات فقط في حالات خاصة.
تباعد الكود
معظم التباعد في Go له معنى، من ناحية ما، هذا يمثل كيف يرى المُترجم الكود، مثلاً في العمليات الحسابية:
2*9 + 1/3*2كما هو معروف، الضرب له أولوية أعلى من الجمع، بعد التنسيق، المسافات حول * ستكون أضيق، مما يعني الأولوية في الحساب، بينما المسافات حول + ستكون أكبر، مما يعني أولوية أقل.
حذف الأقواس المعقوفة
في اللغات الأخرى، عبارات if و for عادةً يمكن اختصارها، هكذا:
for (int i=0; i < 10; i++) printf("%d", i)لكن في Go لا يمكن، يمكنك كتابة سطر واحد فقط، لكن يجب إضافة الأقواس المعقوفة:
for i := 0; i < 10; i++ {fmt.Println(i)}التعبير الثلاثي
لا يوجد في Go تعبير ثلاثي، لذا الكود التالي لن يتم ترجمته:
var c = a > b ? a : bمن خلال هذه المقالة يمكنك الحصول على فهم أولي لقواعد Go، وسيتم شرح المحتوى اللاحق بشكل أكثر تفصيلاً.
