الانتقال إلى المحتوى الرئيسي
الوحدة 6 · الدرس 4 من 529/50 في الدورة~10 min
دروس الوحدة (4/5)

واجهة سترينجر

ربما تكون fmt.Stringer هي الواجهة القياسية الأكثر استخدامًا على الإطلاق مكتبة Go القياسية. إنه العرض المثالي للقوة من الواجهات الصغيرة.

تعريف

Go
type Stringer interface {
    String() string
}

توقيع واحد. أي نوع يحدد String() string يرضي ذلك. ويتعرف fmt على هذه الواجهة: عندما تقوم بتمرير قيمة إلى fmt.Print*، إذا تم تنفيذ Stringer، فإن نتيجة String() يتم استخدامه بدلاً من التمثيل الافتراضي.

مثال

Go
type Point struct{ X, Y int }

func (p Point) String() string {
    return fmt.Sprintf("(%d,%d)", p.X, p.Y)
}

fmt.Println(Point{1, 2})              // (1,2)
fmt.Printf("%v %s\n", Point{3, 4}, Point{5, 6})
// (3,4) (5,6)

تتم طباعة نفس القيمة بتنسيق مخصص في %v، %s، Println، Sprint، log، وما إلى ذلك. كل ذلك فقط من خلال تحديد طريقة واحدة.

عندما يكون من المنطقي

  • الأنواع التي تمثل المجال (المعرفات، والرموز، والإحداثيات، والتعدادات).
  • أخطاء في التمثيل الذي يمكن قراءته بواسطة الإنسان (راجع الدرس التالي في error).
  • الأنواع التي تقوم بتسجيل الدخول إليها كثيرًا والتي تريد تنسيقًا ثابتًا لها.

ليس لكل شيء: إذا كان النوع بسيطًا والتمثيل الافتراضي على ما يرام، لا تضيف الضوضاء.

أنواع التعداد: النمط الشائع مع iota

Go
type Status int

const (
    OK Status = iota
    WARN
    ERR
)

func (s Status) String() string {
    switch s {
    case OK:   return "OK"
    case WARN: return "WARN"
    case ERR:  return "ERR"
    default:   return "UNKNOWN"
    }
}

fmt.Println(OK, WARN, ERR)   // OK WARN ERR

بدون String()، ستتم طباعة fmt.Println(OK) 0. مع String()، يطبع الاسم الرمزي. stringer تقوم الأداة بإنشاء هذا النمط تلقائيًا.

احترس من العودية اللانهائية

Go
type T int
func (t T) String() string {
    return fmt.Sprintf("%d", int(t))  // OK: cast to int breaks the recursion
}

سترينجر على جهاز استقبال المؤشر

إذا كان String() يحتوي على جهاز استقبال للمؤشر، فإن *T فقط يرضي Stringer. باستخدام fmt.Println(t) (قيمة)، ينظر Go إلى مجموعة الأساليب T، لم يجده، ويستخدم التنسيق الافتراضي. لتجنب هذا، قيمة يتم استخدام جهاز الاستقبال عادةً لـ String() (إنه "عرض"؛ لكنه ليس كذلك تعديل أي شيء).

جربه

تمرين#go.m6.l4.e1
المحاولات: 0جارٍ التحميل…

قم بتطبيق String() على النقطة بحيث ترجع (X,Y).

جارٍ تحميل المحرر…
إظهار التلميح

استخدم fmt.Sprintf لتنسيق الحقول.

الحل متاح بعد 3 من المحاولات

تمرين#go.m6.l4.e2
المحاولات: 0جارٍ التحميل…

قم بتنفيذ String() على نوع الحالة (int): 0 → 'OK'، 1 → 'WARN'، وإلا → 'ERR'.

جارٍ تحميل المحرر…
إظهار التلميح

التبديل على قيمة المتلقي. تذكر أن توفر الافتراضي.

الحل متاح بعد 3 من المحاولات

Quiz#go.m6.l4.e3
جاهز

ما هو التوقيع الذي يجب أن تكون عليه الطريقة لإرضاء fmt.Stringer؟

Go
func (x T) ??? {}
خيارات الإجابة

خلاصة

  • محمي_INLINE_29.
  • يؤدي تنفيذه إلى تغيير كيفية تمثيل fmt.Print* للنوع.
  • اصطلاحي للتعدادات (iota)، وأنواع المجال، والرموز/المعرفات.
  • لا تتصل أبدًا بـ fmt.Sprintf("%s", t) على t داخل String() (العودة).
  • الاصطلاح: مستقبل القيمة لـ String() (لا يوجد تغيير، يتجنب "مفاجآت مجموعة الطريقة").