ट्रैक
/
Go
Go
/
अभ्यास
/
लज़ान्या मास्टर
लज़ान्या मास्टर

लज़ान्या मास्टर

सीखने का अभ्यास

परिचय

फंक्शन की मदद से आप कोड को एक ऐसी इकाई में बाँध सकते हैं जिसे दोबारा इस्तेमाल किया जा सकता है। इसमें func कीवर्ड, फंक्शन का नाम, और गोल ब्रैकेट में शून्य या उससे अधिक पैरामीटरों और टाइपों की अल्पविराम से अलग की गई सूची होती है।

फंक्शन के पैरामीटर

हर पैरामीटर का टाइप साफ-साफ लिखना ज़रूरी होता है; पैरामीटर के टाइप का अनुमान नहीं लगाया जा सकता। पैरामीटरों की कोई डिफॉल्ट वैल्यू नहीं होती, इसलिए फंक्शन के सारे पैरामीटर देना ज़रूरी होता है।

import "fmt"

// No parameters
func PrintHello() {
    fmt.Println("Hello")
}

// Two parameters
func PrintGreetingName(greeting string, name string) {
  fmt.Println(greeting + " " + name)
}

एक ही टाइप के पैरामीटरों को साथ-साथ घोषित किया जा सकता है, और उनके बाद एक ही बार टाइप लिखना होता है।

import "fmt"

func PrintGreetingName(greeting, name string) {
  fmt.Println(greeting + " " + name)
}

पैरामीटर और आर्गुमेंट

चलिए जल्दी से दो शब्दों को समझ लेते हैं जिन्हें अक्सर आपस में मिला दिया जाता है: parameters और arguments। फंक्शन के पैरामीटर वे नाम होते हैं जो फंक्शन के सिग्नेचर में परिभाषित होते हैं, जैसे ऊपर दिए गए PrintGreetingName फंक्शन में greeting और name। फंक्शन के आर्गुमेंट वे वास्तविक वैल्यू होती हैं जो फंक्शन को कॉल करते समय उसके पैरामीटरों को दी जाती हैं। जैसे नीचे के उदाहरण में "Hello" और "Katrina" वे आर्गुमेंट हैं जो greeting और name पैरामीटरों को दिए गए हैं:

PrintGreetingName("Hello", "Katrina")

रिटर्न वैल्यू

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

func Hello(name string) string {
  return "Hello " + name
}

func HelloAndGoodbye(name string) (string, string) {
  return "Hello " + name, "Goodbye " + name
}

फंक्शन को कॉल करना

फंक्शन को कॉल करने के लिए उसका नाम लिखा जाता है और गोल ब्रैकेट के अंदर फंक्शन के हर पैरामीटर के लिए आर्गुमेंट दिए जाते हैं।

import "fmt"

// No parameters, no return value
func PrintHello() {
    fmt.Println("Hello")
}
// Called like this:
PrintHello()

// One parameter, one return value
func Hello(name string) string {
  return "Hello " + name
}
// Called like this:
greeting := Hello("Dave")

// Multiple parameters, multiple return values
func SumAndMultiply(a, b int) (int, int) {
    return a+b, a*b
}
// Called like this:
aplusb, atimesb := SumAndMultiply(a, b)

नामित रिटर्न वैल्यू और नेक्ड रिटर्न

पैरामीटरों की तरह रिटर्न वैल्यू को नाम भी दिया जा सकता है, हालाँकि यह ज़रूरी नहीं है। अगर रिटर्न वैल्यू को नाम दिए गए हों, तो बिना आर्गुमेंट वाला return स्टेटमेंट उन्हीं वैल्यू को लौटा देता है। इसे 'नेक्ड' रिटर्न कहते हैं।

func SumAndMultiplyThenMinus(a, b, c int) (sum, mult int) {
    sum, mult = a+b, a*b
    sum -= c
    mult -= c
    return
}

वैल्यू से पास करना और रेफरेंस से पास करना

वैल्यू से पास करने और रेफरेंस से पास करने की धारणा को साफ करना भी ज़रूरी है।

पहले वैल्यू से पास करना समझ लेते हैं। नीचे के उदाहरण में जब हम वेरिएबल val को MultiplyByTwo फंक्शन को पास करते हैं, तो वास्तव में val की एक कॉपी पास होती है। इस वजह से newVal में नई वैल्यू 4 आ जाती है, लेकिन मूल वेरिएबल val अब भी 2 ही रहता है। भीतर ही भीतर Go मूल वैल्यू की एक कॉपी बना देता है, ताकि फंक्शन सिर्फ इसी कॉपी को, यानी v को, बदले।

val := 2
func MultiplyByTwo(v int) int {
    v = v * 2
    return v
}
newVal := MultiplyByTwo(val)
// newval is 4, val is still 2 because only a copy of its value was passed into the function

सख्ती से कहें तो Go में सारे आर्गुमेंट वैल्यू से ही पास होते हैं, यानी फंक्शन को दी गई वैल्यू या डेटा की एक कॉपी बनाई जाती है। लेकिन अगर आप फंक्शन को पास किए गए डेटा की कॉपी नहीं बनाना चाहते और फंक्शन के अंदर उसी डेटा को बदलना चाहते हैं, तो आपको आर्गुमेंट के तौर पर pointers इस्तेमाल करने चाहिए, यानी रेफरेंस से पास करना।

पॉइंटर

रेफरेंस से पास करने के लिए हम pointer का इस्तेमाल करते हैं। फंक्शन को pointer आर्गुमेंट के तौर पर पास करके हम सिर्फ डेटा की कॉपी पर काम करने के बजाय फंक्शन को पास किए गए मूल डेटा को बदल सकते हैं।

फिलहाल इतना जान लेना काफी है कि पॉइंटर टाइप को फंक्शन के सिग्नेचर में टाइप के आगे लगे * से पहचाना जा सकता है।

func HandlePointers(x, y *int) {
    // Some logic to handle integer values referenced by pointers x and y
}

अगर pointer की धारणा उलझी हुई लगे तो कोई बात नहीं। सिलेबस में आगे एक अलग सेक्शन है जो पॉइंटर पर आपकी पकड़ मज़बूत करने में मदद करेगा।

अपवाद

ध्यान दीजिए कि slices और maps ऊपर बताए गए नियम के अपवाद हैं। जब हम किसी फंक्शन को आर्गुमेंट के तौर पर slice या map पास करते हैं, तो उन्हें पॉइंटर टाइप की तरह माना जाता है, भले ही उनके टाइप में कोई साफ * न हो। इसका मतलब है कि अगर हम किसी फंक्शन को स्लाइस या मैप पास करें और उसका मूल डेटा बदलें, तो ये बदलाव मूल स्लाइस या मैप पर भी दिखाई देंगे।

निर्देश

इस अभ्यास में आप अपनी पसंदीदा कुकबुक से शानदार लज़ान्या तैयार करने और पकाने से जुड़ा कुछ और कोड लिखेंगे।

आपके पास चार कार्य हैं। पहला कार्य खुद पकाने से जुड़ा है, बाकी तीन बेहतरीन तैयारी के बारे में हैं।

1. तैयारी के समय का अनुमान लगाइए

अगली बार जब आप लज़ान्या तैयार करेंगे, तो आप यह सुनिश्चित करना चाहते हैं कि आपने पर्याप्त समय बचा रखा हो ताकि आप पकाने का आनंद ले सकें। आप पहले ही तय कर चुके हैं कि आपकी लज़ान्या में कौन-कौन सी परतें होंगी। अब आप उसी के आधार पर अनुमान लगाना चाहते हैं कि तैयारी में कितना समय लगेगा।

एक PreparationTime फंक्शन बनाइए जो परतों की स्लाइस को []string के रूप में और हर परत के औसत तैयारी समय को मिनटों में int के रूप में लेता है। फंक्शन को परतों की संख्या के आधार पर कुल तैयारी समय का अनुमान एक int के रूप में लौटाना चाहिए। Go में फंक्शन के लिए डिफ़ॉल्ट वैल्यू नहीं होती। अगर औसत तैयारी समय 0 के रूप में पास किया जाए (जो एक int की डिफ़ॉल्ट शुरुआती वैल्यू है), तो 2 की डिफ़ॉल्ट वैल्यू इस्तेमाल की जानी चाहिए।

layers := []string{"sauce", "noodles", "sauce", "meat", "mozzarella", "noodles"}
PreparationTime(layers, 3)
// => 18
PreparationTime(layers, 0)
// => 12

2. ज़रूरत वाली नूडल्स और सॉस की मात्रा निकालिए

समय बचाने के अलावा, आप यह भी सुनिश्चित करना चाहते हैं कि आपके पास अपने सपनों की लज़ान्या पकाने के लिए पर्याप्त सॉस और नूडल्स हों। आपकी लज़ान्या में हर नूडल परत के लिए 50 ग्राम नूडल्स चाहिए। आपकी लज़ान्या में हर सॉस परत के लिए 0.2 लीटर सॉस चाहिए।

Quantities फंक्शन बनाइए जो पैरामीटर के रूप में परतों की स्लाइस को []string के रूप में लेता है। फंक्शन फिर अपना खाना बनाने के लिए ज़रूरत वाली नूडल्स और सॉस की मात्रा निकालेगा। परिणाम दो वैल्यू के रूप में लौटाया जाना चाहिए: noodles एक int के रूप में और sauce एक float64 के रूप में।

Quantities([]string{"sauce", "noodles", "sauce", "meat", "mozzarella", "noodles"})
// => 100, 0.4

3. गुप्त सामग्री जोड़िए

कुछ समय पहले आपने एक दोस्त के घर जाकर लज़ान्या खाई थी। वह बहुत बढ़िया थी और उसमें कुछ खास बात थी। दोस्त ने आपको सामग्री की सूची भेजी और बताया कि सूची में अंतिम चीज़ वह "गुप्त सामग्री" है जिसने खाने को इतना खास बनाया। अब आप उस गुप्त सामग्री को अपनी रेसिपी में भी जोड़ना चाहते हैं।

AddSecretIngredient फंक्शन लिखिए जो पैरामीटर के रूप में []string टाइप की सामग्री की दो स्लाइस लेता है। पहला पैरामीटर वह सूची है जो आपके दोस्त ने आपको भेजी, दूसरा आपकी अपनी रेसिपी की सामग्री सूची है। आपकी सामग्री सूची में अंतिम एलिमेंट हमेशा "?" होता है। फंक्शन को इसे आपके दोस्त की सूची के अंतिम आइटम से बदलना चाहिए। ध्यान दें: AddSecretIngredient कुछ नहीं लौटाता, आपको अपनी सामग्री की सूची को सीधे बदलना चाहिए। आपके दोस्त की सामग्री वाली सूची को नहीं बदला जाना चाहिए। साथ ही, चूँकि slice फंक्शन में पॉइंटर के रूप में पास होती है, इसलिए AddSecretIngredient में पास किए गए दो []string आर्गुमेंटों में किए गए बदलाव सीधे लागू होंगे।

friendsList := []string{"noodles", "sauce", "mozzarella", "kampot pepper"}
myList := []string{"noodles", "meat", "sauce", "mozzarella","?"}

AddSecretIngredient(friendsList, myList)
// myList => []string{"noodles", "meat", "sauce", "mozzarella", "kampot pepper"}

4. रेसिपी को स्केल कीजिए

आपकी कुकबुक में दी गई मात्राएँ केवल दो हिस्सों के लिए पर्याप्त लज़ान्या बनाती हैं। चूँकि अगली बार आप अधिक लोगों के लिए खाना बनाना चाहते हैं, आप अलग-अलग हिस्सों की संख्या के लिए मात्राएँ निकालना चाहते हैं।

एक ScaleRecipe फंक्शन बनाइए जो दो पैरामीटर लेता है।

  • 2 हिस्सों के लिए ज़रूरत वाली float64 मात्राओं की एक स्लाइस।
  • आप जितने हिस्सों के लिए खाना बनाना चाहते हैं, उनकी संख्या।

फंक्शन मनचाही संख्या के हिस्सों के लिए ज़रूरत वाली मात्राओं की float64 स्लाइस लौटाए। हालाँकि आप मूल रेसिपी रखना चाहते हैं। इसका मतलब है कि इस फंक्शन में quantities आर्गुमेंट को नहीं बदला जाना चाहिए।

quantities := []float64{ 1.2, 3.6, 10.5 }
scaledQuantities := ScaleRecipe(quantities, 4)
// => []float64{ 2.4, 7.2, 21 }
GitHub के ज़रिए संपादित करें यह लिंक एक नई विंडो या टैब में खुलता है
Go Exercism

लज़ान्या मास्टर शुरू करने के लिए तैयार हैं?

Exercism पर साइन अप कीजिए और Go को 34 कॉन्सेप्ट166 अभ्यास तथा असली इंसानों से मिलने वाली मेंटरिंग के साथ सीखिए और उसमें महारत हासिल कीजिए, वह भी बिल्कुल मुफ्त।