سؤال

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

هل كانت مفيدة؟

المحلول

الذهاب لا تملك معلمات اختيارية ولا تدعم طريقة التحميل الزائد:

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

نصائح أخرى

طريقة لطيفة لتحقيق شيء مثل المعلمات الاختيارية هو استخدام args variadic. تعمل الوظيفة في الواقع شريحة من أي نوع تحدده.

func foo(params ...int) {
    fmt.Println(len(params))
}

func main() {
    foo()
    foo(1)
    foo(1,2,3)
}

يمكنك استخدام منظم يتضمن المعلمات:

type Params struct {
  a, b, c int
}

func doIt(p Params) int {
  return p.a + p.b + p.c 
}

// you can call it without specifying all parameters
doIt(Params{a: 1, c: 9})

بالنسبة للتعسفي، يحتمل أن يكون عدد كبير من المعلمات الاختيارية، وقد تم استخدام المصطلح اللطيف خيارات وظيفية.

لنوعك Foobar, ، أولا كتابة منشئ واحد فقط:

func NewFoobar(options ...func(*Foobar) error) (*Foobar, error){
  fb := &Foobar{}
  // ... (write initializations with default values)...
  for _, op := range options{
    err := op(fb)
    if err != nil {
      return nil, err
    }
  }
  return fb, nil
}

حيث كل خيار هو وظيفة تحرض فوبر. ثم تقديم طرق مريحة لمستخدمك لاستخدام أو إنشاء خيارات قياسية، على سبيل المثال:

func OptionReadonlyFlag(fb *Foobar) error {
  fb.mutable = false
  return nil
}

func OptionTemperature(t Celsius) func(*Foobar) error {
  return func(fb *Foobar) error {
    fb.temperature = t
    return nil
  }
}

ملعب

للحصول على موجزات، يمكنك إعطاء اسم لنوع الخيارات (ملعب) :

type OptionFoobar func(*Foobar) error

إذا كنت بحاجة إلى معلمات إلزامية، فأضفها كحجة أول من المنشئ قبل المتغير options.

الفوائد الرئيسية لل خيارات وظيفية المصطلح هو:

  • يمكن أن تنمو واجهة برمجة التطبيقات الخاصة بك مع مرور الوقت دون كسر التعليمات البرمجية الموجودة، لأن توقيع الشوكسي يبقى كما هو الحاجة إلى خيارات جديدة.
  • انها تمكن من استخدام حالة الاستخدام الافتراضي ليكون أبسط: لا حجج على الإطلاق!
  • يوفر رقابة دقيقة على تهيئة القيم المعقدة.

تم صياغة هذه التقنية من قبل روب بايك وأظهرت أيضا بواسطة ديف تشيني.

لا يتم دعم المعلمات الاختيارية أو التحميل الزائد الوظيفي في الذهاب. اذهب تدعم عدد متغير من المعلمات: اجتياز الحجج إلى ... المعلمات

لا لا. لكل اذهب للمبرمجين C ++ مستندات

اذهب لا يدعم التحميل الزائد الوظيفي ولا يدعم مشغلي المستخدمين المعرفة.

لا يمكنني العثور على بيان واضح على قدم المساواة أن المعلمات الاختيارية غير مدعومة، لكنها غير مدعومة أيضا.

يمكنك تغليف هذا بشكل جيد تماما في موصل مماثلة لما هو أدناه.

package main

import (
        "bufio"
        "fmt"
        "os"
)

func main() {
        fmt.Println(prompt())
}

func prompt(params ...string) string {
        prompt := ": "
        if len(params) > 0 {
                prompt = params[0]
        }
        reader := bufio.NewReader(os.Stdin)
        fmt.Print(prompt)
        text, _ := reader.ReadString('\n')
        return text
}

في هذا المثال، فإن موجه افتراضيا لديه قولون ومسافة أمامه. وبعد وبعد

: 

. وبعد وبعد وبعد ومع ذلك، يمكنك تجاوز ذلك من خلال توفير معلمة إلى الوظيفة السريعة.

prompt("Input here -> ")

سيؤدي ذلك إلى موجه مثل أدناه.

Input here ->

انتهى بي الأمر باستخدام مزيج من هيكل البقارات والدوافير. وبهذه الطريقة، لم يكن لدي تغيير الواجهة الحالية التي استهلكتها العديد من الخدمات وتمكنت خدمتي من اجتياز قدرات إضافية حسب الحاجة. نموذج التعليمات البرمجية في ملعب Golang: https://play.golang.org/p/g668fa97nu.

أنا متأخرة قليلا، ولكن إذا كنت تحب واجهة بطلاقة، فقد تقوم بتصميم setters الخاص بك للمكالمات بالسلاسل مثل هذا:

type myType struct {
  s string
  a, b int
}

func New(s string, err *error) *myType {
  if s == "" {
    *err = errors.New(
      "Mandatory argument `s` must not be empty!")
  }
  return &myType{s: s}
}

func (this *myType) setA (a int, err *error) *myType {
  if *err == nil {
    if a == 42 {
      *err = errors.New("42 is not the answer!")
    } else {
      this.a = a
    }
  }
  return this
}

func (this *myType) setB (b int, _ *error) *myType {
  this.b = b
  return this
}

ثم اتصل به مثل هذا:

func main() {
  var err error = nil
  instance :=
    New("hello", &err).
    setA(1, &err).
    setB(2, &err)

  if err != nil {
    fmt.Println("Failed: ", err)
  } else {
    fmt.Println(instance)
  }
}

هذا مشابه ل خيارات وظيفية Idiom قدمت على الإجابة Ripounet ويتمتع بنفس الفوائد ولكن لديها بعض العيوب:

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

ومع ذلك، هناك ميزة صغيرة محتملة، يجب أن تكون هذه المكالمات هذا النوع من الوظائف أسهل بالنسبة للمترجم المترجم ولكنني في الحقيقة ليس متخصصا.

GO LONGE لا تدعم طريقة التحميل الزائد، ولكن يمكنك استخدام Variadic Args تماما مثل المعلمات الاختيارية، كما يمكنك استخدام واجهة {} كمعلمة ولكنها ليست خيارا جيدا.

يمكنك تمرير المعلمات المسماة التعسفية مع خريطة.

type varArgs map[string]interface{}

func myFunc(args varArgs) {

    arg1 := "default" // optional default value
    if val, ok := args["arg1"]; ok {
        // value override or other action
        arg1 = val.(string) // runtime panic if wrong type
    }

    arg2 := 123 // optional default value
    if val, ok := args["arg2"]; ok {
        // value override or other action
        arg2 = val.(int) // runtime panic if wrong type
    }

    fmt.Println(arg1, arg2)
}

func Test_test() {
    myFunc(varArgs{"arg1": "value", "arg2": 1234})
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top