كيفية تمرير قيمة افتراضية إلى دالة في Go: 5 حلول عملية

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

لماذا لا توجد معاملات افتراضية في Go (وهذا أمر جيد)



تخيل: أنت تكتب بلغة Go وتريد إنشاء دالة بمعامل يمكنك عدم تحديده. كما في Python: def greet(name="ضيف"). تمسك بلوحة المفاتيح وتكتب:



func (u *User) Greet(message string = "مرحباً") string {    return message + ", " + u.Name}


وهنا Go يظهر خطأ. المحول البرمجي يرفض. مألوف؟ هذا السؤال (الأصلي على Stack Overflow حصل على آلاف المشاهدات) يزعج كل مبتدئ ثانٍ في Go. مطورو اللغة تخلوا عمداً عن القيم الافتراضية. لماذا؟ لأن Go هي لغة الوضوح. قابلية قراءة الكود أهم من الاختصار. لكن هذا لا يعني أنك لا تستطيع محاكاة القيمة الافتراضية في Go. هناك على الأقل 5 طرق أنيقة. دعنا نستعرض كل واحدة.



الطريقة 1: التحميل الزائد عبر دوال مختلفة (طريقة Go)



أبسط نهج وأكثر "Go-ية" هو إنشاء دالتين. واحدة بمعامل والأخرى بدونه.



type Config struct {    Timeout int}

func NewDefaultConfig() *Config { return &Config{Timeout: 30} // قيمة افتراضية}

func NewConfig(timeout int) *Config { if timeout <= 0 { timeout = 30 // حماية من الأخطاء } return &Config{Timeout: timeout}}


الإيجابيات: واضح جداً، يُقرأ في ثانية.
السلبيات: مع 3-4 معاملات سيحدث انفجار في عدد الدوال.



الطريقة 2: هيكل مع مُنشئ (نمط البناء Builder Pattern)



عندما تكون المعاملات كثيرة (3+)، يأتي نمط Builder للإنقاذ. هذا هو الأسلوب القياسي في Go للعمل مع المعاملات الاختيارية.



type Server struct {    Host    string    Port    int    Timeout time.Duration    MaxConn int}

// القيم الافتراضيةfunc NewServer() *Server { return &Server{ Host: "localhost", Port: 8080, Timeout: 30 * time.Second, MaxConn: 100, }}

// دوال الضبط (Setters) تعيد الكائن نفسهfunc (s *Server) WithHost(host string) *Server { s.Host = host return s}

func (s *Server) WithPort(port int) *Server { s.Port = port return s}

// الاستخدامserver := NewServer(). WithPort(9090). WithTimeout(10 * time.Second)


هذا النمط يُستخدم بنشاط في المكتبة القياسية لـ Go (مثل http.Server). يحل مشكلة المعاملات الافتراضية في Go بدون اختراقات.



الطريقة 3: المعاملات المتغيرة (Variadic parameters) (خدعة غير متوقعة)



يمكنك استخدام المعاملات المتغيرة (علامة ...). هذه طريقة غير واضحة ولكنها فعالة لمعامل اختياري واحد.



func Greet(name string, opts ...string) string {    greeting := "مرحباً" // قيمة افتراضية    if len(opts) > 0 {        greeting = opts[0]    }    return greeting + ", " + name}

// الاستخدامfmt.Println(Greet("إيفان")) // "مرحباً, إيفان"fmt.Println(Greet("ماريا", "أهلاً")) // "أهلاً, ماريا"


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



الطريقة 4: الخيارات الوظيفية (Functional Options) (الأكثر Go-ية)



هذه هي الطريقة المميزة لمطوري Go. تم نشرها لأول مرة بواسطة ديف تشيني. تتيح تعيين القيمة الافتراضية في Go لأي عدد من المعاملات.



type Option func(*Client)

type Client struct { URL string Timeout time.Duration Retries int}

// القيم الافتراضيةfunc defaultClient() *Client { return &Client{ URL: "https://api.example.com", Timeout: 10 * time.Second, Retries: 3, }}

// الخياراتfunc WithURL(url string) Option { return func(c *Client) { c.URL = url }}

func WithTimeout(t time.Duration) Option { return func(c *Client) {

المدونات

توصيات الكتب