गो में वैकल्पिक पैरामीटर?


464

गो में वैकल्पिक पैरामीटर हो सकते हैं? या क्या मैं एक ही नाम और विभिन्न तर्कों के साथ दो कार्यों को परिभाषित कर सकता हूं?


संबंधित: यह है कि यह वैकल्पिक मापदंडों के रूप में चर का उपयोग करते समय अनिवार्य मापदंडों को लागू करने के लिए कैसे किया जा सकता है: क्या गोलंग में कस्टम लाइब्रेरी के साथ संकलन समय त्रुटि को ट्रिगर करना संभव है?
आईसीजे

11
Google ने एक भयानक निर्णय लिया, क्योंकि कभी-कभी किसी फ़ंक्शन में 90% उपयोग का मामला होता है और फिर 10% उपयोग का मामला होता है। वैकल्पिक arg उस 10% उपयोग के मामले के लिए है। साने डिफॉल्ट का मतलब कम कोड, कम कोड का मतलब ज्यादा रख-रखाव होता है।
जोनाथन

जवाबों:


431

गो में वैकल्पिक पैरामीटर नहीं है और न ही यह ओवरलोडिंग की विधि का समर्थन करता है :

विधि प्रेषण को सरल बनाया जाता है यदि उसे टाइप मिलान करने की आवश्यकता नहीं है। अन्य भाषाओं के साथ अनुभव ने हमें बताया कि एक ही नाम के साथ कई तरह के तरीके हैं लेकिन अलग-अलग हस्ताक्षर कभी-कभी उपयोगी होते हैं लेकिन यह व्यवहार में भ्रामक और नाजुक भी हो सकता है। केवल नाम से मिलान और प्रकारों में निरंतरता की आवश्यकता गो के प्रकार प्रणाली में एक प्रमुख सरलीकरण निर्णय था।


58
है makeएक विशेष मामला तो? या क्या यह वास्तव में एक फ़ंक्शन के रूप में लागू नहीं किया गया है ...
mk12

65
@ Mk12 makeएक भाषा निर्माण है और ऊपर उल्लिखित नियम लागू नहीं होते हैं। इससे संबंधित प्रश्न देखें ।
नीमो

7
rangeइस makeअर्थ में, वैसा ही मामला है
थियागॉफ़क्स

14
विधि अधिभार - अच्छी तरह से लागू होने पर सिद्धांत और उत्कृष्ट में एक महान विचार। हालाँकि, मैंने अभ्यास में
घोर अनिर्णायक

118
मैं एक अंग पर बाहर जाने के लिए और इस पसंद से असहमत हूँ। भाषा डिजाइनरों ने मूल रूप से कहा है, "हम जिस भाषा को चाहते हैं, उसे डिजाइन करने के लिए फ़ंक्शन ओवरलोडिंग की आवश्यकता होती है, इसलिए बनाते हैं, सीमा और इतने पर अनिवार्य रूप से अतिभारित होते हैं, लेकिन यदि आप चाहते हैं कि फ़ंक्शन ओवरलोडिंग एपीआई को डिजाइन करना चाहते हैं, तो ठीक है, यह कठिन है।" तथ्य यह है कि कुछ प्रोग्रामर भाषा सुविधा का दुरुपयोग करते हैं, सुविधा से छुटकारा पाने का तर्क नहीं है।
टॉम

216

वैकल्पिक मापदंडों की तरह कुछ हासिल करने का एक अच्छा तरीका है वैरेडिक आर्ग्स का उपयोग करना। फ़ंक्शन वास्तव में आपके द्वारा निर्दिष्ट किसी भी प्रकार का एक टुकड़ा प्राप्त करता है।

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

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

"फ़ंक्शन वास्तव में आपके द्वारा निर्दिष्ट किसी भी प्रकार का एक टुकड़ा प्राप्त करता है" ऐसा कैसे?
एलिक्स एक्सल

3
उपर्युक्त उदाहरण में, params
चीटियों

76
लेकिन केवल उसी प्रकार के परम के लिए :(
जुआन डे पारास

15
@JuandeParras ठीक है, आप अभी भी कुछ का उपयोग कर सकते हैं ... इंटरफ़ेस {} मुझे लगता है।
मौफ़ल

5
साथ ... प्रकार आप व्यक्तिगत विकल्पों का अर्थ नहीं बता रहे हैं। इसके बजाय एक संरचना का उपयोग करें। ... प्रकार उन मानों के लिए आसान है जिन्हें आपको कॉल से पहले किसी सरणी में रखना होगा।
user3523091

169

आप एक संरचना का उपयोग कर सकते हैं जिसमें पैरामीटर शामिल हैं:

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})

12
यह बहुत अच्छा होगा यदि संरचना में यहां डिफ़ॉल्ट मान हो सकते हैं; उपयोगकर्ता जो कुछ भी छोड़ता है वह उस प्रकार के लिए शून्य मान पर डिफ़ॉल्ट होता है, जो फ़ंक्शन के लिए उपयुक्त डिफ़ॉल्ट तर्क हो सकता है या नहीं हो सकता है।
jsdw

41
@lytnus, मुझे बालों को विभाजित करने से नफरत है, लेकिन जिन क्षेत्रों के लिए मान छोड़ दिए गए हैं, वे उनके प्रकार के लिए 'शून्य मान' को डिफ़ॉल्ट करेंगे; नील एक अलग जानवर है। क्या लोप किए गए फ़ील्ड का प्रकार एक पॉइंटर होना चाहिए, शून्य मान शून्य होगा।
15:11 बजे बुफ़र

2
@burfl हाँ, "शून्य मान" की धारणा को छोड़कर int / float / string प्रकारों के लिए बिल्कुल बेकार है, क्योंकि वे मान सार्थक हैं और इसलिए आप यह अंतर नहीं बता सकते हैं कि क्या मूल्य संरचना से छोड़ा गया था या यदि शून्य मान था जानबूझकर पास हुआ।
कीमोन

3
@keymone, मैं आपसे असहमत नहीं हूं। मैं केवल उस स्टेटमेंट के बारे में पांडित्यपूर्ण हो रहा था, जो उपयोगकर्ता द्वारा "उस प्रकार के लिए शून्य मान" के लिए डिफ़ॉल्ट रूप से छोड़ा गया है, जो गलत है। वे शून्य मान के लिए डिफ़ॉल्ट हैं, जो कि एक सूचक है या नहीं, इसके आधार पर शून्य हो सकता है या नहीं।
बुर्फ़

123

मनमाने ढंग से, संभावित रूप से बड़ी संख्या में वैकल्पिक मापदंडों के लिए, एक अच्छा मुहावरा कार्यात्मक विकल्पों का उपयोग करना है ।

अपने प्रकार के लिए 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

कार्यात्मक विकल्प मुहावरे के मुख्य लाभ हैं:

  • मौजूदा कोड को तोड़ने के बिना आपका एपीआई समय के साथ बढ़ सकता है, क्योंकि नए विकल्पों की आवश्यकता होने पर कॉन्स्टक्टर हस्ताक्षर वही रहता है।
  • यह डिफ़ॉल्ट उपयोग के मामले को अपने सबसे सरल होने में सक्षम बनाता है: कोई तर्क नहीं!
  • यह जटिल मूल्यों के आरंभ पर ठीक नियंत्रण प्रदान करता है।

यह तकनीक रॉब पाइक द्वारा गढ़ी गई थी और डेव चेनी द्वारा भी प्रदर्शित की गई थी ।



15
चतुर, लेकिन बहुत जटिल। गो का दर्शन एक सरल तरीके से कोड लिखना है। बस एक संरचना पास करें और डिफ़ॉल्ट मानों के लिए परीक्षण करें।
user3523091

9
सिर्फ FYI करें, इस मुहावरे के मूल लेखक, कम से कम पहले प्रकाशक संदर्भित हैं, कमांडर रॉब पाइक हैं, जिन्हें मैं गो दर्शन के लिए आधिकारिक रूप से पर्याप्त मानता हूं। लिंक - Commandcenter.blogspot.bg/2014/01/… । "सरल जटिल है" के लिए भी खोजें।
पेटार डोनचेव

2
#JMTCW, लेकिन मुझे इस दृष्टिकोण के बारे में तर्क देना बहुत मुश्किल है। मैं अब तक मूल्यों की एक संरचना में गुजरना पसंद करूंगा, जिसके गुण func()अगर जरूरत पड़ सकते हैं, तो इस दृष्टिकोण से अपने मस्तिष्क को मोड़ सकते हैं। जब भी मुझे इस दृष्टिकोण का उपयोग करना होता है, जैसे कि इको लाइब्रेरी के साथ, मुझे लगता है कि मेरा मस्तिष्क गर्भपात के खरगोश के छेद में फंस गया है। # एफवी
माइकस्किंकेल

धन्यवाद, इस मुहावरे की तलाश थी। के रूप में अच्छी तरह से स्वीकार किए जाते हैं जवाब के रूप में वहाँ हो सकता है।
r --------- k


6

न - न। C ++ प्रोग्रामर डॉक्स के लिए प्रति गो ,

जाओ फ़ंक्शन ओवरलोडिंग का समर्थन नहीं करता है और उपयोगकर्ता परिभाषित ऑपरेटरों का समर्थन नहीं करता है।

मैं समान रूप से स्पष्ट कथन नहीं ढूँढ सकता कि वैकल्पिक पैरामीटर असमर्थित हैं, लेकिन वे समर्थित नहीं हैं।


8
"इस [वैकल्पिक मापदंडों] के लिए कोई वर्तमान योजना नहीं है।" इयान लांस टेलर, गो भाषा टीम। groups.google.com/group/golang-nuts/msg/030e63e7e681fd3e
peterSO

कोई भी उपयोगकर्ता परिभाषित ऑपरेटर एक भयानक निर्णय नहीं है, क्योंकि यह किसी भी चालाक गणित पुस्तकालय के पीछे मूल है, जैसे कि रैखिक उत्पादों और रैखिक बीजगणित के लिए क्रॉस उत्पादों, अक्सर 3 डी ग्राफिक्स में उपयोग किया जाता है।
जोनाथन

4

आप नीचे दिए गए एक फंक के समान इसे अच्छी तरह से अलग कर सकते हैं।

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 ->

3

मैंने पैरामस और वैरेडिक आर्ग्स की संरचना के संयोजन का उपयोग करके समाप्त किया। इस तरह, मुझे मौजूदा इंटरफ़ेस को बदलना नहीं पड़ा जो कि कई सेवाओं द्वारा खपत किया गया था और मेरी सेवा आवश्यकतानुसार अतिरिक्त पैरामेट्स पास करने में सक्षम थी। गोलंग खेल के मैदान में नमूना कोड: https://play.golang.org/p/G668FA97Nu


3

गो भाषा, ओवरलोडिंग की विधि का समर्थन नहीं करती है, लेकिन आप वैरिएबल आर्ग्स का उपयोग वैकल्पिक मापदंडों की तरह कर सकते हैं, साथ ही आप इंटरफ़ेस {} को पैरामीटर के रूप में उपयोग कर सकते हैं लेकिन यह एक अच्छा विकल्प नहीं है।


2

मुझे थोड़ी देर हो गई है, लेकिन यदि आप धाराप्रवाह इंटरफ़ेस पसंद करते हैं, तो आप इस तरह से जंजीर कॉल के लिए अपने बसने को डिज़ाइन कर सकते हैं:

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)
  }
}

यह @Ripounet उत्तर पर प्रस्तुत कार्यात्मक विकल्प मुहावरे के समान है और समान लाभ प्राप्त करता है लेकिन इसमें कुछ कमियां हैं:

  1. यदि कोई त्रुटि होती है तो वह तुरंत निरस्त नहीं होगी, इसलिए, यदि आप अपने निर्माता से अक्सर त्रुटियों की रिपोर्ट करने की अपेक्षा करते हैं तो यह थोड़ा कम कुशल होगा।
  2. आपको एक errवैरिएबल घोषित करने और इसे शून्य करने के लिए एक लाइन खर्च करनी होगी ।

हालांकि, एक संभावित छोटा लाभ है, इस प्रकार के फ़ंक्शन कॉल को इनलाइनर इनलाइन के लिए आसान होना चाहिए लेकिन मैं वास्तव में विशेषज्ञ नहीं हूं।


यह एक बिल्डर पैटर्न है
UmNyobe

2

आप नक्शे के साथ मनमाने ढंग से नामित मापदंडों को पारित कर सकते हैं।

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})
}

यहाँ इस दृष्टिकोण पर कुछ टिप्पणी है: reddit.com/r/golang/comments/546g4z/…
nobar


0

एक अन्य संभावना एक संरचना का उपयोग करने के लिए होगी जो यह इंगित करने के लिए फ़ील्ड के साथ है कि क्या यह वैध है। NullString जैसे sql से अशक्त प्रकार सुविधाजनक हैं। अपने स्वयं के प्रकार को परिभाषित न करने के लिए अच्छा है, लेकिन यदि आपको एक कस्टम डेटा प्रकार की आवश्यकता है तो आप हमेशा उसी पैटर्न का पालन कर सकते हैं। मुझे लगता है कि वैकल्पिक-परिभाषा फ़ंक्शन परिभाषा से स्पष्ट है और न्यूनतम अतिरिक्त कोड या प्रयास है।

उदहारण के लिए:

func Foo(bar string, baz sql.NullString){
  if !baz.Valid {
        baz.String = "defaultValue"
  }
  // the rest of the implementation
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.