फंक्शन की मदद से आप कोड को एक ऐसी इकाई में बाँध सकते हैं जिसे दोबारा इस्तेमाल किया जा सके।
इसमें func कीवर्ड, फंक्शन का नाम, और गोल ब्रैकेट के अंदर कॉमा से अलग किए गए शून्य या अधिक पैरामीटर और उनके टाइप होते हैं।
हर पैरामीटर का टाइप साफ-साफ लिखना पड़ता है, पैरामीटर के लिए टाइप का अनुमान नहीं लगाया जाता। पैरामीटर के लिए कोई डिफॉल्ट वैल्यू नहीं होती, इसलिए फंक्शन के सारे पैरामीटर देना ज़रूरी है।
import "fmt"
// No parameters
func PrintHello() {
fmt.Println("Hello")
}
// One parameter
func PrintHelloName(name string) {
fmt.Println("Hello " + 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 आर्गुमेंट के तौर पर देते हैं, तो उन्हें पॉइंटर टाइप की तरह माना जाता है, भले ही टाइप में कोई साफ * न लिखा हो।
इसका मतलब है कि अगर हम फंक्शन को स्लाइस या मैप देते हैं और उसका मूल डेटा बदलते हैं,
तो ये बदलाव मूल स्लाइस या मैप में भी दिखेंगे।
Go में फंक्शन को फर्स्ट क्लास सिटिज़न माना जाता है, जो उन्हें बहुत शक्तिशाली बनाता है। फंक्शन से जुड़े कई और कॉन्सेप्ट भी हैं, जैसे मेथड और अनाम फंक्शन, जिनसे आप आगे चलकर मिलेंगे।