Menu
flag Ar iconالعربيةdown icon

تأكيد النوع في Golang: x.(T) وcomma-ok وtype switch

يستخرج تأكيد النوع القيمة المحدّدة من واجهة. تعلّم x.(T)، وصيغة comma-ok التي لا تسبّب panic أبدًا، والتأكيد إلى واجهة أخرى، وtype switch، وerrors.As للأخطاء المغلّفة.

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

x.(T): استخراج القيمة من واجهة

تخفي قيمة الواجهة النوع المحدّد الذي تحمله. ويطلب تأكيد النوع x.(T) استعادته.

المخرجات:

gopher 6
0 false
string of length 6

يجب أن يكون لـ x نوع واجهة. التأكيد على نوع محدّد يفشل في الترجمة: invalid operation: s (variable of type string) is not an interface.

الصيغة ذات القيمة الواحدة تسبّب panic

عندما يكون التأكيد خاطئًا، تسبّب الصيغة ذات القيمة الواحدة panic برسالة تسمّي النوعين:

المخرجات:

recovered: interface conversion: interface {} is int, not string

استخدم الصيغة ذات القيمة الواحدة فقط عندما يكون النوع المختلف خطأ برمجيًا تريد أن ينهار البرنامج بسببه. وفي كل مكان آخر استخدم comma-ok. عند الفشل تعطي comma-ok القيمة الصفرية لـ T وfalse.

التأكيد على واجهة nil يفشل أيضًا: تسبّب var v any; v.(string) حالة panic برسالة interface conversion: interface {} is nil, not string، وتعيد صيغة comma-ok القيمتين "", false.

التأكيد إلى واجهة أخرى

يمكن أن يكون T نوع واجهة. ينجح التأكيد عندها إذا كانت القيمة الديناميكية تطبّق T، وتحتفظ النتيجة بالقيمة الديناميكية نفسها. هكذا تتحقّق المكتبة القياسية من القدرات الاختيارية.

تتحقّق io.Copy من أن مصدرها يطبّق io.WriterTo وتستخدمه إن فعل. وتتحقّق fmt من Stringer وerror. يتيح هذا النمط للواجهة الصغيرة أن تبقى صغيرة بينما يستفيد المستدعون من التطبيقات الأغنى.

type switch

عندما قد تكون القيمة أحد عدة أنواع، يحلّ type switch محل سلسلة من التأكيدات. والصيغة x.(type) صالحة فقط داخل switch.

المخرجات:

hi
integer 7
integer 8
3.14
nil
error: boom
unhandled []int

قواعد تستحق المعرفة:

  • في حالة بنوع واحد يكون لـ x ذلك النوع. وفي حالة تسرد عدة أنواع، وفي default، يكون لـ x نوع الواجهة الأصلية (any هنا).
  • تُفحص الحالات بالترتيب. ضع الواجهات الأكثر تحديدًا قبل الأعم، لأن القيمة قد تحقّق عدة واجهات.
  • لا تطابق case nil إلا واجهة nil، لا واجهة تحمل مؤشرًا nil.
  • لا يوجد fallthrough في type switch.

errors.As: التأكيد للأخطاء المغلّفة

تُغلَّف الأخطاء غالبًا مع سياق: fmt.Errorf("load config: %w", err). التأكيد المباشر لا ينظر إلا إلى الخطأ الخارجي ويفوّت الذي بداخله. أما errors.As فتمشي على السلسلة.

المخرجات:

type assertion finds it: false
errors.As finds it: open /no/such/file

استخدم تأكيد النوع على الأخطاء فقط عندما تعرف أن الخطأ غير مغلّف، وهذا عمليًا يعني تقريبًا أبدًا. تشرح صفحة الأخطاء المخصّصة errors.As وerrors.Is وتعريف أنواع أخطائك.

التأكيدات مقابل التحويلات مقابل الأنواع العامة

لديكتريداستخدم
intfloat64تحويل: float64(n)
any يحمل intالـ intتأكيد: v.(int)
any من عدة أنواع ممكنةالتفرّع حسب النوعtype switch
error قد يكون مغلّفًانوع خطأ محدّدerrors.As
دالة تعمل مع أنواع كثيرةأمان وقت الترجمةالأنواع العامة

الشيفرة المليئة بـ any وtype switch كثيرًا ما تكون علامة على أن الأنواع العامة أو واجهة مناسبة ستعبّر عن القصد أفضل وتلتقط الأخطاء وقت الترجمة.

أخطاء شائعة

  • استخدام الصيغة المسبّبة لـ panic على بيانات غير موثوقة. JSON المفكوك، وقيم الخرائط من النوع any، ومدخلات الإضافات: استخدم comma-ok دائمًا.
  • التأكيد إلى النوع الرقمي الخطأ. تُفكّ أرقام JSON إلى any كـ float64، فتفشل v.(int) معها.
  • تأكيد نوع قيمة عندما يكون المخزّن مؤشرًا. إذا كانت الواجهة تحمل *User، تفشل v.(User). أكّد v.(*User).
  • تأكيدات النوع على الأخطاء. استخدم errors.As.

الأسئلة الشائعة

ما هو تأكيد النوع في Go؟

تعبير x.(T) حيث x قيمة واجهة. إذا كان T نوعًا محدّدًا، يعيد القيمة المخزّنة في x بالنوع T. وإذا كان T نوع واجهة، يتحقّق من أن القيمة المخزّنة تطبّق T أيضًا. الصيغة ذات القيمة الواحدة تسبّب panic عند فشل الفحص؛ والصيغة ذات القيمتين v, ok := x.(T) تبلغ عنه في ok.

كيف أعرف نوع قيمة واجهة في Go؟

استخدم type switch: switch v := x.(type) { case int: ...; case string: ...; default: ... }. داخل كل حالة يكون لـ v نوع تلك الحالة. ولنوع واحد يكون تأكيد comma-ok s, ok := x.(string) أقصر. وتطبع fmt.Printf("%T", x) اسم النوع لتتبّع الأخطاء.

ما الفرق بين تأكيد النوع وتحويل النوع في Go؟

يحوّل التحويل T(x) قيمة من نوع إلى آخر، مثل float64(n)؛ ويقرّر المترجم هل هو مسموح، ولا يمكن أن يفشل وقت التشغيل. أما التأكيد x.(T) فيعمل فقط على قيم الواجهات ويتحقّق وقت التشغيل من النوع المخزّن بداخلها. لا يمكنك كتابة int(x) لقيمة any تحمل int؛ تحتاج x.(int).

هل أستخدم تأكيد النوع لفحص أنواع الأخطاء؟

لا. استخدم errors.As(err, &target). التأكيد المباشر err.(*MyError) لا ينظر إلا إلى الخطأ الخارجي، فيفشل حالما يُغلَّف الخطأ بـ fmt.Errorf("...: %w", err). أما errors.As فتمشي على سلسلة التغليف.

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن