محتويات الدورة

Go / المتوسط: الحزم والعمل المتزامن / الدرس 7

الحزم وحدود الواجهات

صمم حزما مترابطة بعقود عامة صغيرة واعتمادات صريحة ومتطلبات وحدات قابلة للتكرار.

وقت القراءة التقريبي: 4 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • فصل هوية الحزمة من إصدارات الوحدة.
  • استخدام الظهور والمنشئات لحماية الثوابت.
  • اختيار الاعتمادات دون دورات استيراد.

الحزمة وحدة مسؤولية

تجمع الحزمة شيفرة ذات غرض مترابط ومسار استيراد واحد. قد تضم الوحدة حزما عديدة وتصدرها معا. اجعل اسم الحزمة موجزا وأسماءها المكشوفة واضحة عند الاستدعاء. تجنب util ضخمة بمساعدات غير مترابطة تنشئ عقد اعتماد وتخفي الملكية.

ترفض Go دورات الاستيراد. بدلا من نقل الملفات عشوائيا حتى يصمت المترجم حدد اتجاه الاعتماد المفهومي. تتيح واجهة صغيرة يملكها المستهلك اعتماد المنطق العالي على السلوك مع محول مستقل للتخزين أو النقل. اربط القطع الملموسة عند حدود الأمر.

إخفاء الحالات غير الصالحة خلف العمليات

يُكشف المعرف البادئ بحرف كبير من الحزمة؛ ويكون الصغير خاصا بالحزمة لا بملف واحد. تتيح الحقول الخاصة للمنشئات والطرق فرض العلاقات. يمثل المثال الأول كمية غير سالبة بمنشئ يرفض السالب. يجعله الملف الواحد قابلا للتشغيل مستقلا؛ وتنشر الحزمة الحقيقية الواجهة المقصودة فقط.

القيمة الصفرية كمية صالحة هنا أيضا. قد يفيد المنشئ دون إلزام. وإذا تطلب النوع تهيئة فوثقها وتجنب إعادة صفر غير قابل للاستخدام في مسار فشل قد يخلطه المستدعي بالنجاح.

go عملية عامة حول ثابت خاص
package main

import (
	"errors"
	"fmt"
)

type Quantity struct{ value int }

func NewQuantity(value int) (Quantity, error) {
	if value < 0 {
		return Quantity{}, errors.New("negative quantity")
	}
	return Quantity{value: value}, nil
}
func (q Quantity) Value() int { return q.value }

func main() {
	q, err := NewQuantity(7)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("quantity", q.Value())
}
الناتج المتوقع
quantity 7

يقبل المنشئ سبعة ويلاحظها المستدعي عبر طريقة القراءة.

تمرير الاعتمادات صراحة

قد تكون الاعتمادات قيما وواجهات بدلا من عموميات الحزمة. تستطيع دالة تقبل io.Writer إرسال الخرج لمخزن في الاختبار وملف في الأمر. يحتاج المستهلك عقد Write فقط لا كل كاتب ملموس. هذا تمرير معاملات عادي لا إطار خاص.

يفحص المثال الثاني نتيجة الكتابة ويعيد الخطأ للمستدعي. ولا ينهي العملية من مساعد قابل للاستخدام. يجب توثيق إغلاق المورد المملوك؛ وقبول io.Writer لا يعني عادة إغلاق كاتب لم تنشئه الدالة.

go اعتماد إخراج محقون ضيق
package main

import (
	"bytes"
	"fmt"
	"io"
)

func greet(w io.Writer, name string) error {
	_, err := fmt.Fprintf(w, "hello %s\n", name)
	return err
}

func main() {
	var output bytes.Buffer
	if err := greet(&output, "Ada"); err != nil {
		fmt.Println(err)
		return
	}
	fmt.Print(output.String())
}
الناتج المتوقع
hello Ada

تحقق bytes.Buffer واجهة io.Writer فيُفحص المساعد دون طرفية أو ملف.

تسجيل معنى الاعتماد لا الملفات فقط

يسجل go.mod متطلبات الوحدات وتوجيهاتها، ويسجل go.sum بصمات محتواها لا ملف قفل تقليديا كاملا لكل مدخل بناء. يتبع الاختيار قواعد Go الموثقة. لا يعني طلب وحدة أن كل حزمها الانتقالية مستخدمة أو أن كل منصة تختار الملفات نفسها.

راجع تغييرات الاعتمادات عمدا وأبق بيانات الوحدات متسقة. يقيد اصطلاح internal من يجوز له استيراد حزم التنفيذ. يضع الإصدار الدلالي للاستيراد الإصدارات الكبرى v2 وما بعدها في مسار الوحدات المعتادة؛ فقد يتطلب تغيير الواجهة الكبرى تغيير المسارات والمتطلبات معا.

يشمل التوافق السلوك

قد يكسر توقيع ثابت المستدعين إذا تغير التعديل أو الترتيب أو هوية الخطأ أو الإلغاء أو الملكية. وثق الخصائص قرب التصريحات المكشوفة. لا تبدأ حزمة كانت تعيد بيانات مستقلة بإعادة شريحة مشتركة قابلة للتعديل دون مراجعة عقدها.

أبق إعداد الأمر والتسجيل وسياسة إنهاء العملية خارج الحزم المعاد استخدامها قدر الإمكان. اختبر السلوك المكشوف مع اختبارات داخلية مركزة للثوابت المعقدة. يسهل حفظ واجهة صغيرة ومراجعتها وتطويرها أكثر من واجهة تكشف كل تسهيلات التنفيذ.

الأخطاء الشائعة وإصلاحها

تستورد حزمتان بعضهما.

لماذا يحدث؟
تشابكت المسؤوليات واتجاه الاعتماد.
كيف تصلحه؟
استخرج تجريدا مشتركا مترابطا أو احقن واجهة المستهلك.
كيف تتجنب تكراره؟
راجع مخطط الاستيراد قبل إضافة معرفة متبادلة.

يغلق مساعد خرج المستدعي دون توقع.

لماذا يحدث؟
اختلطت الاستعارة بالملكية.
كيف تصلحه؟
اترك الكاتب المستعار مفتوحا ما لم ينقل العقد المسؤولية.
كيف تتجنب تكراره؟
وثق ملكية الإنشاء والإغلاق.

يحفظ تعديل الأنواع لكنه يكسر المستهلكين.

لماذا يحدث؟
تغيرت الوعود السلوكية دون مراجعة.
كيف تصلحه؟
استعد السلوك أو نفذ انتقال توافق مقصودا.
كيف تتجنب تكراره؟
اختبر الملكية والأخطاء والترتيب عند الحدود العامة.

اختبر فهمك

1. تستخدم حزمة كاتبا عاما وتستدعي os.Exit عند فشل الكتابة. أعد تصميم حدودها.

اعرض الحل المشروح

اقبل io.Writer كمعامل أو اعتماد منشأ وأعد خطأ الكتابة. ليقرر الأمر التسجيل والخروج. تحقن الاختبارات bytes.Buffer وكاتبا اصطناعيا يفشل. يجعل ذلك الفشل قابلا للملاحظة دون قتل الاختبار ويمنع افتراض ملكية كاتب المستدعي.

2. لماذا يوثق منشئ ينسخ شريحة هل النسخ سطحي؟

اعرض الحل المشروح

يفصل النسخ الخارجي المصفوفة الخلفية لكن عناصر المؤشرات والخرائط والشرائح قد تبقى مشتركة. يحتاج المستدعي معرفة التعديلات المعزولة. يكفي نسخ عناصر []int لاستقلالها؛ وللسجلات الأغنى اختر سياسة نسخ داخلي أو استعارة واختبرها صراحة.

أهم ما تعلمته

  • تملك الحزم المسؤوليات والوحدات حدود التوزيع ذي الإصدار.
  • يسهل اختبار اعتماد ضيق أكثر من سلوك عام خفي.
  • يشمل التوافق الملكية والأخطاء والترتيب والأنواع.

المراجع الرسمية