गोलांग ट्यूटोरियल
गो क्या है?
Go (जिसे गोलंग के नाम से भी जाना जाता है) गूगल द्वारा विकसित एक ओपन सोर्स प्रोग्रामिंग भाषा है। यह एक स्टेटिकली-टाइप्ड संकलित भाषा है। गो समवर्ती प्रोग्रामिंग का समर्थन करता है, यानी यह एक साथ कई प्रक्रियाओं को चलाने की अनुमति देता है। यह चैनल, गोरूटीन आदि का उपयोग करके प्राप्त किया जाता है। गो भाषा में कचरा संग्रहण है जो स्वयं मेमोरी प्रबंधन करता है और कार्यों के विलंबित निष्पादन की अनुमति देता है।
हम इस गो भाषा ट्यूटोरियल में गोलैंग की सभी मूल बातें सीखेंगे।
GO को कैसे डाउनलोड और इंस्टॉल करें
चरण 1) https://golang.org/dl/अपने ओएस के लिए बाइनरी डाउनलोड करें।
चरण 2) Double इंस्टॉलर पर क्लिक करें और चलाएँ पर क्लिक करें।
चरण 3) अगला पर क्लिक करें
चरण 4) स्थापना फ़ोल्डर का चयन करें और अगला क्लिक करें.
चरण 5) स्थापना पूर्ण हो जाने पर समाप्त पर क्लिक करें।
चरण 6) एक बार इंस्टॉलेशन पूरा हो जाने पर आप टर्मिनल खोलकर और टाइप करके इसे सत्यापित कर सकते हैं
go version
यह स्थापित go का संस्करण प्रदर्शित करेगा
आपका पहला गो कार्यक्रम - गो हेलो वर्ल्ड!
studyGo नाम का एक फ़ोल्डर बनाएँ। इस Go भाषा ट्यूटोरियल में, हम इस फ़ोल्डर के अंदर अपने go प्रोग्राम बनाएंगे। Go फ़ाइलें एक्सटेंशन के साथ बनाई जाती हैं ।जाओ. आप सिंटैक्स का उपयोग करके गो प्रोग्राम चला सकते हैं
go run <filename>
first.go नाम से एक फ़ाइल बनाएं और उसमें नीचे दिया गया कोड डालें और सेव करें
package main import ("fmt") func main() { fmt.Println("Hello World! This is my first Go program\n") }
अपने टर्मिनल में इस फ़ोल्डर पर जाएँ। कमांड का उपयोग करके प्रोग्राम चलाएँ
पहले भागो जाओ.
आप आउटपुट प्रिंटिंग देख सकते हैं
Hello World! This is my first Go program
अब आइये उपरोक्त कार्यक्रम पर चर्चा करें।
पैकेज मेन - प्रत्येक गो भाषा प्रोग्राम को पैकेज नाम से शुरू होना चाहिए। गो हमें दूसरे गो प्रोग्राम में पैकेज का उपयोग करने की अनुमति देता है और इसलिए कोड पुनः प्रयोज्यता का समर्थन करता है। गो प्रोग्राम का निष्पादन पैकेज के अंदर मेन नामक कोड से शुरू होता है।
import fmt – पैकेज fmt को आयात करता है। यह पैकेज I/O फ़ंक्शन को लागू करता है।
func main() – यह वह फ़ंक्शन है जिससे प्रोग्राम निष्पादन शुरू होता है। main फ़ंक्शन को हमेशा main पैकेज में रखा जाना चाहिए। main() के अंतर्गत, आप { } के अंदर कोड लिख सकते हैं।
fmt.Println – यह fmt के Println फ़ंक्शन द्वारा स्क्रीन पर टेक्स्ट प्रिंट करेगा।
नोट: इस गो ट्यूटोरियल के नीचे के अनुभागों में, जब आप कोड को निष्पादित/चलाने का उल्लेख करते हैं, तो इसका मतलब है कि कोड को .go एक्सटेंशन वाली फ़ाइल में सहेजना और सिंटैक्स का उपयोग करके इसे चलाना
go run <filename>
जानकारी का प्रकार
प्रकार (डेटा प्रकार) किसी चर में संग्रहीत मान के प्रकार, फ़ंक्शन द्वारा लौटाए जाने वाले मान के प्रकार आदि को दर्शाते हैं।
गो भाषा में तीन मूल प्रकार हैं
संख्यात्मक प्रकार - संख्यात्मक मानों को प्रदर्शित करें जिसमें पूर्णांक, फ़्लोटिंग पॉइंट और जटिल मान शामिल हैं। विभिन्न संख्यात्मक प्रकार हैं:
int8 – 8 बिट हस्ताक्षरित पूर्णांक.
int16 – 16 बिट हस्ताक्षरित पूर्णांक.
int32 – 32 बिट हस्ताक्षरित पूर्णांक.
int64 – 64 बिट हस्ताक्षरित पूर्णांक.
uint8 – 8 बिट अहस्ताक्षरित पूर्णांक.
uint16 – 16 बिट अहस्ताक्षरित पूर्णांक.
uint32 – 32 बिट अहस्ताक्षरित पूर्णांक.
uint64 – 64 बिट अहस्ताक्षरित पूर्णांक.
float32 – 32 बिट फ़्लोटिंग पॉइंट संख्याएँ.
float64 – 64 बिट फ़्लोटिंग पॉइंट संख्याएँ.
complex64 - में float32 वास्तविक और काल्पनिक भाग होते हैं।
complex128 - में float32 वास्तविक और काल्पनिक भाग होते हैं।
स्ट्रिंग प्रकार - बाइट्स (अक्षरों) के अनुक्रम का प्रतिनिधित्व करता है। आप स्ट्रिंग पर विभिन्न ऑपरेशन कर सकते हैं जैसे स्ट्रिंग संयोजन, सबस्ट्रिंग निकालना, आदि
बूलियन प्रकार - दो मानों को दर्शाता है, या तो सत्य या असत्य।
गोलांग इंटरफ़ेस
गोलांग इंटरफ़ेस ऑब्जेक्ट के व्यवहार को लागू करने के लिए टाइप द्वारा उपयोग किए जाने वाले विधि हस्ताक्षरों का एक संग्रह है। Golang इंटरफ़ेस का मुख्य लक्ष्य नाम, तर्क और रिटर्न प्रकार के साथ विधि हस्ताक्षर प्रदान करना है। विधि को घोषित करना और लागू करना टाइप पर निर्भर करता है। Golang में इंटरफ़ेस को “इंटरफ़ेस” कीवर्ड का उपयोग करके घोषित किया जा सकता है।
चर
वेरिएबल्स मेमोरी लोकेशन की ओर इशारा करते हैं जो किसी तरह का मान संग्रहीत करता है। टाइप पैरामीटर (नीचे दिए गए सिंटैक्स में) उस मान के प्रकार को दर्शाता है जिसे मेमोरी लोकेशन में संग्रहीत किया जा सकता है।
सिंटैक्स का उपयोग करके चर घोषित किया जा सकता है
var <variable_name> <type>
एक बार जब आप किसी प्रकार का चर घोषित कर देते हैं तो आप उस प्रकार के किसी भी मान को चर में निर्दिष्ट कर सकते हैं।
आप घोषणा के दौरान ही किसी चर को आरंभिक मान भी दे सकते हैं
var <variable_name> <type> = <value>
यदि आप किसी आरंभिक मान के साथ चर घोषित करते हैं, तो Go असाइन किए गए मान के प्रकार से चर के प्रकार का अनुमान लगा सकता है। इसलिए आप सिंटैक्स का उपयोग करके घोषणा के दौरान प्रकार को छोड़ सकते हैं
var <variable_name> = <value>
इसके अलावा, आप सिंटैक्स के साथ कई चर घोषित कर सकते हैं
var <variable_name1>, <variable_name2> = <value1>, <value2>
इस गो ट्यूटोरियल में नीचे दिए गए प्रोग्राम में चर घोषणाओं के कुछ Golang उदाहरण दिए गए हैं
package main import "fmt" func main() { //declaring a integer variable x var x int x=3 //assigning x the value 3 fmt.Println("x:", x) //prints 3 //declaring a integer variable y with value 20 in a single statement and prints it var y int=20 fmt.Println("y:", y) //declaring a variable z with value 50 and prints it //Here type int is not explicitly mentioned var z=50 fmt.Println("z:", z) //Multiple variables are assigned in single line- i with an integer and j with a string var i, j = 100,"hello" fmt.Println("i and j:", i,j) }
आउटपुट होगा
x: 3 y: 20 z: 50 i and j: 100 hello
गो लैंग्वेज var कीवर्ड को छोड़ कर मान के साथ वेरिएबल्स को घोषित करने का एक आसान तरीका भी प्रदान करता है
<variable_name> := <value>
ध्यान दें कि आपने उपयोग किया := के बजाय =आप := का उपयोग किसी ऐसे चर को मान निर्दिष्ट करने के लिए नहीं कर सकते जो पहले से ही घोषित है। := का उपयोग मान घोषित करने और निर्दिष्ट करने के लिए किया जाता है।
निम्नलिखित कोड के साथ assignment.go नामक एक फ़ाइल बनाएँ
package main import ("fmt") func main() { a := 20 fmt.Println(a) //gives error since a is already declared a := 30 fmt.Println(a) }
परिणाम देखने के लिए go run assignment.go निष्पादित करें
./assign.go:7:4: no new variables on left side of :=
प्रारंभिक मान के बिना घोषित चर का मान संख्यात्मक प्रकार के लिए 0, बूलियन के लिए गलत और स्ट्रिंग के लिए रिक्त स्ट्रिंग होगा
स्थिरांक
स्थिर चर वे चर होते हैं जिनका मान एक बार असाइन किए जाने के बाद बदला नहीं जा सकता। गो प्रोग्रामिंग भाषा में स्थिरांक को “const” कीवर्ड का उपयोग करके घोषित किया जाता है
constant.go नाम से एक फ़ाइल बनाएं और निम्नलिखित कोड का उपयोग करें
package main import ("fmt") func main() { const b =10 fmt.Println(b) b = 30 fmt.Println(b) }
परिणाम देखने के लिए go run constant.go निष्पादित करें
.constant.go:7:4: cannot assign to b
फॉर लूप उदाहरण
लूप का उपयोग किसी शर्त के आधार पर कथनों के ब्लॉक को बार-बार निष्पादित करने के लिए किया जाता है। अधिकांश प्रोग्रामिंग भाषाएँ 3 प्रकार के लूप प्रदान करती हैं - for, while, do while। लेकिन गो प्रोग्रामिंग भाषा केवल फॉर लूप का समर्थन करती है।
गोलांग फॉर लूप का सिंटैक्स है
for initialisation_expression; evaluation_expression; iteration_expression{ // one or more statement }
प्रारंभिक अभिव्यक्ति (इनिशियलाइजेशन_एक्सप्रेशन) को सबसे पहले (और केवल एक बार) गोलांग फॉर लूप में निष्पादित किया जाता है।
फिर evaluate_expression का मूल्यांकन किया जाता है और यदि यह सत्य है तो ब्लॉक के अंदर का कोड निष्पादित किया जाता है।
iteration_expression id निष्पादित की जाती है, और evaluate_expression का फिर से मूल्यांकन किया जाता है। यदि यह सत्य है तो कथन ब्लॉक फिर से निष्पादित होता है। यह तब तक जारी रहेगा जब तक evaluate_expression असत्य नहीं हो जाता।
नीचे दिए गए प्रोग्राम को एक फ़ाइल में कॉपी करें और इसे निष्पादित करें ताकि Golang for loop द्वारा 1 से 5 तक की संख्याएँ प्रिंट होते हुए देखा जा सके
package main import "fmt" func main() { var i int for i = 1; i <= 5; i++ { fmt.Println(i) } }
आउटपुट है
1 2 3 4 5
यदि अन्यथा
यदि else एक सशर्त कथन है। इसका वाक्यविन्यास है
if condition{ // statements_1 }else{ // statements_2 }
यहां शर्त का मूल्यांकन किया जाता है और यदि यह सत्य है तो statement_1 निष्पादित किया जाएगा अन्यथा statement_2 निष्पादित किया जाएगा।
आप बिना else also के if स्टेटमेंट का उपयोग कर सकते हैं। आप चेन किए गए if else स्टेटमेंट भी रख सकते हैं। नीचे दिए गए प्रोग्राम if else के बारे में अधिक जानकारी देंगे।
नीचे दिए गए प्रोग्राम को निष्पादित करें। यह जाँचता है कि क्या कोई संख्या, x, 10 से कम है। यदि ऐसा है, तो यह “x 10 से कम है” प्रिंट करेगा
package main import "fmt" func main() { var x = 50 if x < 10 { //Executes if x < 10 fmt.Println("x is less than 10") } }
यहाँ चूँकि x का मान 10 से अधिक है, इसलिए if ब्लॉक स्थिति के अंदर कथन निष्पादित नहीं होगा।
अब नीचे दिए गए प्रोग्राम को देखें। इस गो प्रोग्रामिंग भाषा ट्यूटोरियल में, हमारे पास एक else ब्लॉक है जो if मूल्यांकन के विफल होने पर निष्पादित होगा।
package main import "fmt" func main() { var x = 50 if x < 10 { //Executes if x is less than 10 fmt.Println("x is less than 10") } else { //Executes if x >= 10 fmt.Println("x is greater than or equals 10") } }
यह प्रोग्राम आपको आउटपुट देगा
x is greater than or equals 10
अब इस गो ट्यूटोरियल में, हम एक प्रोग्राम देखेंगे जिसमें कई if else ब्लॉक (चेन if else) होंगे। नीचे दिए गए गो उदाहरण को निष्पादित करें। यह जाँचता है कि कोई संख्या 10 से कम है या 10-90 के बीच है या 90 से अधिक है।
package main import "fmt" func main() { var x = 100 if x < 10 { //Executes if x is less than 10 fmt.Println("x is less than 10") } else if x >= 10 && x <= 90 { //Executes if x >= 10 and x<=90 fmt.Println("x is between 10 and 90") } else { //Executes if both above cases fail i.e x>90 fmt.Println("x is greater than 90") } }
यहाँ सबसे पहले if कंडीशन यह जाँचती है कि x 10 से कम है या नहीं और यह नहीं है। इसलिए यह अगली कंडीशन (else if) की जाँच करता है कि क्या यह 10 और 90 के बीच है जो कि गलत भी है। इसलिए यह else सेक्शन के अंतर्गत ब्लॉक को निष्पादित करता है जो आउटपुट देता है
x is greater than 90
स्विच
स्विच एक और सशर्त कथन है। स्विच कथन एक अभिव्यक्ति का मूल्यांकन करते हैं और परिणाम की तुलना उपलब्ध मानों (मामलों) के एक सेट के साथ की जाती है। एक बार जब कोई मिलान मिल जाता है तो उस मिलान (मामले) से जुड़े कथनों को निष्पादित किया जाता है। यदि कोई मिलान नहीं मिलता है तो कुछ भी निष्पादित नहीं किया जाएगा। आप स्विच में एक डिफ़ॉल्ट केस भी जोड़ सकते हैं जो तब निष्पादित होगा जब कोई अन्य मिलान नहीं मिलता है। स्विच का सिंटैक्स है
switch expression { case value_1: statements_1 case value_2: statements_2 case value_n: statements_n default: statements_default }
यहाँ अभिव्यक्ति के मान की तुलना प्रत्येक मामले में मानों से की जाती है। एक बार मिलान मिल जाने पर उस मामले से जुड़े कथनों को निष्पादित किया जाता है। यदि कोई मिलान नहीं मिलता है तो डिफ़ॉल्ट अनुभाग के अंतर्गत कथनों को निष्पादित किया जाता है।
नीचे दिए गए प्रोग्राम को निष्पादित करें
package main import "fmt" func main() { a,b := 2,1 switch a+b { case 1: fmt.Println("Sum is 1") case 2: fmt.Println("Sum is 2") case 3: fmt.Println("Sum is 3") default: fmt.Println("Printing default") } }
आपको आउटपुट इस प्रकार मिलेगा
Sum is 3
a और b का मान 3 में बदलें और परिणाम होगा
Printing default
आप एक केस में एकाधिक मानों को अल्पविराम से अलग करके भी रख सकते हैं।
Arrays
ऐरे एक निश्चित आकार, एक ही प्रकार के तत्वों के नामित अनुक्रम का प्रतिनिधित्व करता है। आपके पास ऐसा ऐरे नहीं हो सकता जिसमें पूर्णांक और वर्ण दोनों हों। एक बार आकार निर्धारित करने के बाद आप ऐरे का आकार नहीं बदल सकते।
किसी सारणी को घोषित करने का सिंटैक्स है
var arrayname [size] type
प्रत्येक सारणी तत्व को सिंटैक्स का उपयोग करके मान निर्दिष्ट किया जा सकता है
arrayname [index] = value
सारणी सूचकांक यहाँ से शुरू होता है 0 से आकार-1.
आप सिंटैक्स का उपयोग करके घोषणा के दौरान सरणी तत्वों को मान निर्दिष्ट कर सकते हैं
arrayname := [size] type {value_0,value_1,…,value_size-1}
आप array को मानों के साथ घोषित करते समय size को से प्रतिस्थापित करके size पैरामीटर को अनदेखा भी कर सकते हैं ... और संकलक मानों की संख्या से लंबाई ज्ञात करेगा। वाक्यविन्यास है
arrayname := […] type {value_0,value_1,…,value_size-1}
आप सिंटैक्स का उपयोग करके सरणी की लंबाई ज्ञात कर सकते हैं
len(arrayname)
सरणी को समझने के लिए नीचे दिए गए Go उदाहरण को निष्पादित करें
package main import "fmt" func main() { var numbers [3] string //Declaring a string array of size 3 and adding elements numbers[0] = "One" numbers[1] = "Two" numbers[2] = "Three" fmt.Println(numbers[1]) //prints Two fmt.Println(len(numbers)) //prints 3 fmt.Println(numbers) // prints [One Two Three] directions := [...] int {1,2,3,4,5} // creating an integer array and the size of the array is defined by the number of elements fmt.Println(directions) //prints [1 2 3 4 5] fmt.Println(len(directions)) //prints 5 //Executing the below commented statement prints invalid array index 5 (out of bounds for 5-element array) //fmt.Println(directions[5]) }
उत्पादन
Two 3 [One Two Three] [1 2 3 4 5] 5
गोलांग स्लाइस और एपेंड फ़ंक्शन
स्लाइस किसी सरणी का एक भाग या खंड होता है। या यह किसी अंतर्निहित सरणी का दृश्य या आंशिक दृश्य होता है, जिसकी ओर यह इंगित करता है। आप स्लाइस नाम और इंडेक्स नंबर का उपयोग करके स्लाइस के तत्वों तक पहुँच सकते हैं, ठीक वैसे ही जैसे आप सरणी में करते हैं। आप सरणी की लंबाई नहीं बदल सकते, लेकिन आप स्लाइस का आकार बदल सकते हैं।
स्लाइस की सामग्री वास्तव में एक सरणी के तत्वों के लिए संकेत हैं। इसका मतलब है यदि आप स्लाइस में कोई भी तत्व बदलते हैं, तो अंतर्निहित सरणी सामग्री भी प्रभावित होगी।
स्लाइस बनाने के लिए सिंटैक्स है
var slice_name [] type = array_name[start:end]
यह array_name नामक सरणी से slice_name नामक एक स्लाइस बनाएगा, जिसमें सूचकांक start से end-1 तक के तत्व होंगे।
अब इस Golang ट्यूटोरियल में, हम नीचे दिए गए प्रोग्राम को निष्पादित करेंगे। प्रोग्राम ऐरे से एक स्लाइस बनाएगा और उसे प्रिंट करेगा। साथ ही, आप देख सकते हैं कि स्लाइस में सामग्री को संशोधित करने से वास्तविक ऐरे संशोधित हो जाएगा।
package main import "fmt" func main() { // declaring array a := [5] string {"one", "two", "three", "four", "five"} fmt.Println("Array after creation:",a) var b [] string = a[1:4] //created a slice named b fmt.Println("Slice after creation:",b) b[0]="changed" // changed the slice data fmt.Println("Slice after modifying:",b) fmt.Println("Array after slice modification:",a) }
इससे परिणाम इस प्रकार प्रिंट होगा
Array after creation: [one two three four five] Slice after creation: [two three four] Slice after modifying: [changed three four] Array after slice modification: [one changed three four five]
कुछ फ़ंक्शन हैं जैसे कि Golang len, Golang append जिन्हें आप स्लाइस पर लागू कर सकते हैं
लेन(स्लाइस_नाम) - स्लाइस की लंबाई लौटाता है
(स्लाइस_नाम, मान_1, मान_2) जोड़ें – Golang append का उपयोग किसी मौजूदा स्लाइस में value_1 और value_2 को जोड़ने के लिए किया जाता है।
(स्लाइस_नाले1,स्लाइस_नाम2…) जोड़ें – स्लाइस_नाम2 को स्लाइस_नाम1 में जोड़ता है
निम्नलिखित प्रोग्राम निष्पादित करें.
package main import "fmt" func main() { a := [5] string {"1","2","3","4","5"} slice_a := a[1:3] b := [5] string {"one","two","three","four","five"} slice_b := b[1:3] fmt.Println("Slice_a:", slice_a) fmt.Println("Slice_b:", slice_b) fmt.Println("Length of slice_a:", len(slice_a)) fmt.Println("Length of slice_b:", len(slice_b)) slice_a = append(slice_a,slice_b...) // appending slice fmt.Println("New Slice_a after appending slice_b :", slice_a) slice_a = append(slice_a,"text1") // appending value fmt.Println("New Slice_a after appending text1 :", slice_a) }
आउटपुट होगा
Slice_a: [2 3] Slice_b: [two three] Length of slice_a: 2 Length of slice_b: 2 New Slice_a after appending slice_b : [2 3 two three] New Slice_a after appending text1 : [2 3 two three text1]
प्रोग्राम पहले 2 स्लाइस बनाता है और उसकी लंबाई प्रिंट करता है। फिर एक स्लाइस को दूसरे स्लाइस से जोड़ता है और फिर परिणामी स्लाइस में एक स्ट्रिंग जोड़ता है।
कार्य
फ़ंक्शन कथनों के एक ब्लॉक का प्रतिनिधित्व करता है जो एक विशिष्ट कार्य करता है। फ़ंक्शन घोषणा हमें फ़ंक्शन का नाम, रिटर्न प्रकार और इनपुट पैरामीटर बताती है। फ़ंक्शन परिभाषा फ़ंक्शन में निहित कोड का प्रतिनिधित्व करती है। फ़ंक्शन घोषित करने के लिए सिंटैक्स है
func function_name(parameter_1 type, parameter_n type) return_type { //statements }
पैरामीटर और रिटर्न प्रकार वैकल्पिक हैं। साथ ही, आप फ़ंक्शन से कई मान लौटा सकते हैं।
अब इस Golang ट्यूटोरियल में, आइए निम्नलिखित Golang उदाहरण चलाते हैं। यहाँ calc नामक फ़ंक्शन 2 संख्याएँ स्वीकार करेगा और जोड़ और घटाव करेगा और दोनों मान लौटाएगा।
package main import "fmt" //calc is the function name which accepts two integers num1 and num2 //(int, int) says that the function returns two values, both of integer type. func calc(num1 int, num2 int)(int, int) { sum := num1 + num2 diff := num1 - num2 return sum, diff } func main() { x,y := 15,10 //calls the function calc with x and y an d gets sum, diff as output sum, diff := calc(x,y) fmt.Println("Sum",sum) fmt.Println("Diff",diff) }
आउटपुट होगा
Sum 25 Diff 5
संकुल
पैकेज का उपयोग कोड को व्यवस्थित करने के लिए किया जाता है। किसी बड़े प्रोजेक्ट में, एक ही फ़ाइल में कोड लिखना संभव नहीं है। गो प्रोग्रामिंग भाषा हमें कोड को अलग-अलग पैकेज के तहत व्यवस्थित करने की अनुमति देती है। इससे कोड की पठनीयता और पुन: प्रयोज्यता बढ़ जाती है। एक निष्पादन योग्य गो प्रोग्राम में main नामक पैकेज होना चाहिए और प्रोग्राम का निष्पादन main नामक फ़ंक्शन से शुरू होता है। आप सिंटैक्स का उपयोग करके हमारे प्रोग्राम में अन्य पैकेज आयात कर सकते हैं
import package_name
हम इस Golang ट्यूटोरियल में देखेंगे और चर्चा करेंगे कि निम्नलिखित Golang उदाहरण में पैकेज कैसे बनाएं और उनका उपयोग कैसे करें।
चरण 1) package_example.go नामक एक फ़ाइल बनाएं और नीचे दिया गया कोड जोड़ें
package main import "fmt" //the package to be created import "calculation" func main() { x,y := 15,10 //the package will have function Do_add() sum := calculation.Do_add(x,y) fmt.Println("Sum",sum) }
उपरोक्त प्रोग्राम में fmt एक पैकेज है जो गो प्रोग्रामिंग भाषा हमें मुख्य रूप से I/O उद्देश्यों के लिए प्रदान करती है। इसके अलावा, आप calculations नामक एक पैकेज देख सकते हैं। main() के अंदर आप एक स्टेप sum := calculations.Do_add(x,y) देख सकते हैं। इसका मतलब है कि आप पैकेज calculations से Do_add फ़ंक्शन को इनवोक कर रहे हैं।
चरण 2) सबसे पहले, आपको go के src फ़ोल्डर के अंतर्गत समान नाम वाले फ़ोल्डर के अंदर पैकेज कैलकुलेशन बनाना चाहिए। go का इंस्टॉल किया गया पथ PATH वैरिएबल से पाया जा सकता है।
मैक के लिए, echo $PATH निष्पादित करके पथ ढूंढें
तो पथ है /usr/local/go
विंडोज़ के लिए, echo %GOROOT% निष्पादित करके पथ ढूंढें
यहाँ पथ है C:\Go\
चरण 3) src फ़ोल्डर पर जाएँ (मैक के लिए /usr/local/go/src और विंडोज़ के लिए C:\Go\src)। अब कोड से, पैकेज का नाम calculations है। Go के लिए आवश्यक है कि पैकेज को src निर्देशिका के अंतर्गत समान नाम की निर्देशिका में रखा जाए। src फ़ोल्डर में calculations नाम की एक निर्देशिका बनाएँ।
चरण 4) calculations डायरेक्टरी के अंदर calc.go नामक एक फ़ाइल बनाएं (आप कोई भी नाम दे सकते हैं, लेकिन कोड में पैकेज का नाम मायने रखता है। यहाँ यह calculations होना चाहिए) और नीचे दिया गया कोड जोड़ें
package calculation func Do_add(num1 int, num2 int)(int) { sum := num1 + num2 return sum }
चरण 5) गणना निर्देशिका से go install कमांड चलाएँ जो calc.go को संकलित करेगा।
चरण 6) अब package_example.go पर वापस जाएँ और go run package_example.go चलाएँ। आउटपुट Sum 25 होगा।
ध्यान दें कि फ़ंक्शन Do_add का नाम कैपिटल लेटर से शुरू होता है। ऐसा इसलिए है क्योंकि गो में अगर फ़ंक्शन का नाम कैपिटल लेटर से शुरू होता है तो इसका मतलब है कि दूसरे प्रोग्राम इसे देख (एक्सेस) सकते हैं, अन्यथा दूसरे प्रोग्राम इसे एक्सेस नहीं कर सकते। अगर फ़ंक्शन का नाम do_add होता, तो आपको यह त्रुटि मिलती
निर्यात न किए गए नाम calculations.calc. को संदर्भित नहीं किया जा सकता.
स्थगित करना और स्थगित करना
डिफर स्टेटमेंट का उपयोग फ़ंक्शन कॉल के निष्पादन को तब तक स्थगित करने के लिए किया जाता है जब तक कि डिफर स्टेटमेंट वाला फ़ंक्शन निष्पादन पूरा नहीं कर लेता।
आइये इसे एक उदाहरण से सीखें:
package main import "fmt" func sample() { fmt.Println("Inside the sample()") } func main() { //sample() will be invoked only after executing the statements of main() defer sample() fmt.Println("Inside the main()") }
आउटपुट होगा
Inside the main() Inside the sample()
यहां sample() का निष्पादन तब तक स्थगित कर दिया जाता है जब तक कि संलग्न फ़ंक्शन(main()) का निष्पादन पूरा नहीं हो जाता।
डिफर को स्टैक करना कई डिफर स्टेटमेंट का उपयोग करना है। मान लीजिए कि आपके पास फ़ंक्शन के अंदर कई डिफर स्टेटमेंट हैं। Go सभी डिफर्ड फ़ंक्शन कॉल को स्टैक में रखता है, और एक बार संलग्न फ़ंक्शन वापस आ जाता है, स्टैक किए गए फ़ंक्शन को निष्पादित किया जाता है अंतिम आगमन प्रथम आगमन (LIFO) क्रम। आप इसे नीचे दिए गए उदाहरण में देख सकते हैं।
नीचे दिए गए कोड को निष्पादित करें
package main import "fmt" func display(a int) { fmt.Println(a) } func main() { defer display(1) defer display(2) defer display(3) fmt.Println(4) }
आउटपुट होगा
4 3 2 1
यहां main() के अंदर का कोड पहले निष्पादित होता है, और फिर स्थगित फ़ंक्शन कॉल विपरीत क्रम में निष्पादित होते हैं, अर्थात 4, 3,2,1।
संकेत
पॉइंटर्स को समझाने से पहले आइए पहले '&' ऑपरेटर पर चर्चा करें। '&' ऑपरेटर का उपयोग किसी वेरिएबल का पता प्राप्त करने के लिए किया जाता है। इसका मतलब है कि '&a' वेरिएबल a का मेमोरी एड्रेस प्रिंट करेगा।
इस गोलांग ट्यूटोरियल में, हम एक चर का मान और उस चर का पता प्रदर्शित करने के लिए नीचे दिए गए प्रोग्राम को निष्पादित करेंगे
package main import "fmt" func main() { a := 20 fmt.Println("Address:",&a) fmt.Println("Value:",a) }
परिणाम होगा
Address: 0xc000078008 Value: 20
पॉइंटर वैरिएबल दूसरे वैरिएबल का मेमोरी एड्रेस स्टोर करता है। आप सिंटैक्स का उपयोग करके पॉइंटर को परिभाषित कर सकते हैं
var variable_name *type
तारांकन चिह्न (*) दर्शाता है कि चर एक पॉइंटर है। नीचे दिए गए प्रोग्राम को निष्पादित करके आप अधिक समझ पाएंगे
package main import "fmt" func main() { //Create an integer variable a with value 20 a := 20 //Create a pointer variable b and assigned the address of a var b *int = &a //print address of a(&a) and value of a fmt.Println("Address of a:",&a) fmt.Println("Value of a:",a) //print b which contains the memory address of a i.e. &a fmt.Println("Address of pointer b:",b) //*b prints the value in memory address which b contains i.e. the value of a fmt.Println("Value of pointer b",*b) //increment the value of variable a using the variable b *b = *b+1 //prints the new value using a and *b fmt.Println("Value of pointer b",*b) fmt.Println("Value of a:",a)}
आउटपुट होगा
Address of a: 0x416020 Value of a: 20 Address of pointer b: 0x416020 Value of pointer b 20 Value of pointer b 21 Value of a: 21
संरचनाएं
संरचना एक उपयोगकर्ता द्वारा परिभाषित डेटा प्रकार है जिसमें स्वयं समान या भिन्न प्रकार का एक और तत्व शामिल होता है।
संरचना का उपयोग एक 2 चरण की प्रक्रिया है।
सबसे पहले, एक संरचना प्रकार बनाएं(घोषित करें)
दूसरा, मानों को संग्रहीत करने के लिए उस प्रकार के चर बनाएं।
संरचनाओं का उपयोग मुख्य रूप से तब किया जाता है जब आप संबंधित डेटा को एक साथ संग्रहीत करना चाहते हैं।
कर्मचारी की जानकारी के एक हिस्से पर विचार करें जिसमें नाम, आयु और पता शामिल है। आप इसे 2 तरीकों से संभाल सकते हैं
तीन सरणियाँ बनाएँ - एक सरणियाँ कर्मचारियों के नाम संग्रहीत करती हैं, एक आयु संग्रहीत करती है और तीसरी सरणियाँ आयु संग्रहीत करती हैं।
3 फ़ील्ड के साथ एक संरचना प्रकार घोषित करें- नाम, पता और आयु। उस संरचना प्रकार की एक सरणी बनाएँ जहाँ प्रत्येक तत्व एक संरचना ऑब्जेक्ट है जिसमें नाम, पता और आयु है।
पहला तरीका कारगर नहीं है। इस तरह के परिदृश्यों में, संरचनाएँ अधिक सुविधाजनक होती हैं।
संरचना घोषित करने के लिए वाक्यविन्यास है
type structname struct { variable_1 variable_1_type variable_2 variable_2_type variable_n variable_n_type }
संरचना घोषणा का एक उदाहरण है
type emp struct { name string address string age int }
यहाँ emp नामक एक नया उपयोगकर्ता परिभाषित प्रकार बनाया गया है। अब, आप सिंटैक्स का उपयोग करके emp प्रकार के चर बना सकते हैं
var variable_name struct_name
एक उदाहरण है
var empdata1 emp
आप empdata1 के लिए मान इस प्रकार सेट कर सकते हैं
empdata1.name = "John" empdata1.address = "Street-1, Bangalore" empdata1.age = 30
आप एक संरचना चर भी बना सकते हैं और उसके द्वारा मान निर्दिष्ट कर सकते हैं
empdata2 := emp{"Raj", "Building-1, Delhi", 25}
यहाँ, आपको तत्वों के क्रम को बनाए रखने की आवश्यकता है। राज को नाम से, अगले तत्व को पते से और अंतिम तत्व को आयु से मैप किया जाएगा।
नीचे दिए गए कोड को निष्पादित करें
package main import "fmt" //declared the structure named emp type emp struct { name string address string age int } //function which accepts variable of emp type and prints name property func display(e emp) { fmt.Println(e.name) } func main() { // declares a variable, empdata1, of the type emp var empdata1 emp //assign values to members of empdata1 empdata1.name = "John" empdata1.address = "Street-1, London" empdata1.age = 30 //declares and assign values to variable empdata2 of type emp empdata2 := emp{"Raj", "Building-1, Paris", 25} //prints the member name of empdata1 and empdata2 using display function display(empdata1) display(empdata2) }
उत्पादन
John Raj
विधियाँ(फ़ंक्शन नहीं)
विधि एक फ़ंक्शन है जिसमें एक रिसीवर तर्क होता है। Archiतकनीकी रूप से, यह func कीवर्ड और विधि नाम के बीच है। विधि का सिंटैक्स है
func (variable variabletype) methodName(parameter1 paramether1type) { }
आइए उपरोक्त उदाहरण प्रोग्राम को फ़ंक्शन के बजाय विधियों का उपयोग करने के लिए परिवर्तित करें।
package main import "fmt" //declared the structure named emp type emp struct { name string address string age int } //Declaring a function with receiver of the type emp func(e emp) display() { fmt.Println(e.name) } func main() { //declaring a variable of type emp var empdata1 emp //Assign values to members empdata1.name = "John" empdata1.address = "Street-1, Lodon" empdata1.age = 30 //declaring a variable of type emp and assign values to members empdata2 := emp { "Raj", "Building-1, Paris", 25} //Invoking the method using the receiver of the type emp // syntax is variable.methodname() empdata1.display() empdata2.display() }
गो एक ऑब्जेक्ट ओरिएंटेड भाषा नहीं है और इसमें क्लास की अवधारणा नहीं है। मेथड्स आपको यह अहसास कराते हैं कि आप ऑब्जेक्ट ओरिएंटेड प्रोग्राम में क्या करते हैं, जहाँ क्लास के फंक्शन को सिंटैक्स objectname.functionname() का उपयोग करके बुलाया जाता है।
संगामिति
गो कार्यों के समवर्ती निष्पादन का समर्थन करता है। इसका मतलब है कि गो एक साथ कई कार्यों को निष्पादित कर सकता है। यह समानांतरता की अवधारणा से अलग है। समानांतरता में, एक कार्य को छोटे उप-कार्यों में विभाजित किया जाता है और समानांतर में निष्पादित किया जाता है। लेकिन समवर्तीता में, कई कार्यों को एक साथ निष्पादित किया जा रहा है। गो में समवर्तीता गोराउटिन और चैनल का उपयोग करके प्राप्त की जाती है।
गोरोउटिन्स
गोरूटीन एक ऐसा फ़ंक्शन है जो अन्य फ़ंक्शन के साथ समवर्ती रूप से चल सकता है। आमतौर पर जब किसी फ़ंक्शन को इनवोक किया जाता है तो नियंत्रण कॉल किए गए फ़ंक्शन में स्थानांतरित हो जाता है, और एक बार इसका निष्पादन पूरा हो जाने पर नियंत्रण कॉलिंग फ़ंक्शन पर वापस आ जाता है। फिर कॉलिंग फ़ंक्शन अपना निष्पादन जारी रखता है। कॉलिंग फ़ंक्शन बाकी कथनों के साथ आगे बढ़ने से पहले इनवोक किए गए फ़ंक्शन के निष्पादन को पूरा करने की प्रतीक्षा करता है।
लेकिन गोरूटीन के मामले में, कॉलिंग फ़ंक्शन इनवोक किए गए फ़ंक्शन के निष्पादन के पूरा होने का इंतज़ार नहीं करेगा। यह अगले कथनों के साथ निष्पादित करना जारी रखेगा। आप एक प्रोग्राम में कई गोरूटीन रख सकते हैं।
इसके अलावा, मुख्य प्रोग्राम अपने कथनों का निष्पादन पूरा करने के बाद बाहर निकल जाएगा और यह आह्वान किए गए गोरूटीन के पूरा होने की प्रतीक्षा नहीं करेगा।
गोरूटीन को गो कीवर्ड के बाद फ़ंक्शन कॉल का उपयोग करके बुलाया जाता है।
उदाहरण
go add(x,y)
नीचे दिए गए Golang उदाहरणों से आप गोरूटीन को समझ पाएंगे। नीचे दिए गए प्रोग्राम को निष्पादित करें
package main import "fmt" func display() { for i:=0; i<5; i++ { fmt.Println("In display") } } func main() { //invoking the goroutine display() go display() //The main() continues without waiting for display() for i:=0; i<5; i++ { fmt.Println("In main") } }
आउटपुट होगा
In main In main In main In main In main
यहाँ मुख्य प्रोग्राम ने गोरूटीन शुरू होने से पहले ही निष्पादन पूरा कर लिया। डिस्प्ले() एक गोरूटीन है जिसे सिंटैक्स का उपयोग करके बुलाया जाता है
go function_name(parameter list)
उपरोक्त कोड में, main() display() के पूरा होने का इंतज़ार नहीं करता है, और main() ने display() के कोड को निष्पादित करने से पहले ही अपना निष्पादन पूरा कर लिया। इसलिए display() के अंदर प्रिंट स्टेटमेंट प्रिंट नहीं हुआ।
अब हम डिस्प्ले() से स्टेटमेंट प्रिंट करने के लिए प्रोग्राम को संशोधित करते हैं। हम main() के for loop में 2 सेकंड का समय विलंब और डिस्प्ले() के for loop में 1 सेकंड का विलंब जोड़ते हैं।
package main import "fmt" import "time" func display() { for i:=0; i<5; i++ { time.Sleep(1 * time.Second) fmt.Println("In display") } } func main() { //invoking the goroutine display() go display() for i:=0; i<5; i++ { time.Sleep(2 * time.Second) fmt.Println("In main") } }
आउटपुट कुछ इस प्रकार होगा
In display In main In display In display In main In display In display In main In main In main
यहां आप देख सकते हैं कि समवर्ती निष्पादन के कारण दोनों लूप ओवरलैपिंग फैशन में निष्पादित हो रहे हैं।
चैनल
चैनल फ़ंक्शन के लिए एक दूसरे के साथ संवाद करने का एक तरीका है। इसे एक माध्यम के रूप में सोचा जा सकता है जहाँ एक रूटीन डेटा रखता है और Golang सर्वर में दूसरे रूटीन द्वारा एक्सेस किया जाता है।
एक चैनल को सिंटैक्स के साथ घोषित किया जा सकता है
channel_variable := make(chan datatype)
उदाहरण:
ch := make(chan int)
आप सिंटैक्स का उपयोग करके किसी चैनल पर डेटा भेज सकते हैं
channel_variable <- variable_name
उदाहरण
ch <- x
आप सिंटैक्स का उपयोग करके किसी चैनल से डेटा प्राप्त कर सकते हैं
variable_name := <- channel_variable
उदाहरण
y := <- ch
ऊपर दिए गए गो भाषा के गोरूटीन के उदाहरणों में, आपने देखा है कि मुख्य प्रोग्राम गोरूटीन की प्रतीक्षा नहीं करता है। लेकिन जब चैनल शामिल होते हैं तो ऐसा नहीं होता है। मान लीजिए कि अगर कोई गोरूटीन चैनल पर डेटा भेजता है, तो main() चैनल डेटा प्राप्त करने वाले कथन पर तब तक प्रतीक्षा करेगा जब तक कि उसे डेटा नहीं मिल जाता।
आप इसे नीचे दिए गए गो भाषा उदाहरणों में देखेंगे। सबसे पहले, एक सामान्य गोरूटीन लिखें और व्यवहार देखें। फिर चैनल का उपयोग करने के लिए प्रोग्राम को संशोधित करें और व्यवहार देखें।
नीचे दिए गए प्रोग्राम को निष्पादित करें
package main import "fmt" import "time" func display() { time.Sleep(5 * time.Second) fmt.Println("Inside display()") } func main() { go display() fmt.Println("Inside main()") }
आउटपुट होगा
Inside main()
main() ने निष्पादन समाप्त कर दिया और goroutine के निष्पादन से पहले ही बाहर निकल गया। इसलिए display() के अंदर प्रिंट निष्पादित नहीं हुआ।
अब चैनलों का उपयोग करने के लिए उपरोक्त प्रोग्राम को संशोधित करें और व्यवहार देखें।
package main import "fmt" import "time" func display(ch chan int) { time.Sleep(5 * time.Second) fmt.Println("Inside display()") ch <- 1234 } func main() { ch := make(chan int) go display(ch) x := <-ch fmt.Println("Inside main()") fmt.Println("Printing x in main() after taking from channel:",x) }
आउटपुट होगा
Inside display() Inside main() Printing x in main() after taking from channel: 1234
यहाँ क्या होता है कि x := <-ch पर पहुँचने पर main() चैनल ch पर डेटा के लिए प्रतीक्षा करेगा। display() में 5 सेकंड की प्रतीक्षा होती है और फिर चैनल ch पर डेटा पुश करता है। चैनल से डेटा प्राप्त करने पर main() अनब्लॉक हो जाता है और अपना निष्पादन जारी रखता है।
चैनल पर डेटा भेजने वाला प्रेषक चैनल बंद करके रिसीवर को सूचित कर सकता है कि चैनल में कोई और डेटा नहीं जोड़ा जाएगा। इसका उपयोग मुख्य रूप से तब किया जाता है जब आप चैनल पर डेटा भेजने के लिए लूप का उपयोग करते हैं। चैनल को बंद करने के लिए
close(channel_name)
और रिसीवर छोर पर, चैनल से डेटा प्राप्त करते समय एक अतिरिक्त चर का उपयोग करके यह जांचना संभव है कि चैनल बंद है या नहीं
variable_name, status := <- channel_variable
यदि स्थिति सत्य है तो इसका मतलब है कि आपको चैनल से डेटा प्राप्त हुआ है। यदि गलत है तो इसका मतलब है कि आप बंद चैनल से पढ़ने का प्रयास कर रहे हैं
आप गोरूटीन के बीच संचार के लिए चैनल का भी उपयोग कर सकते हैं। 2 गोरूटीन का उपयोग करने की आवश्यकता है - एक चैनल पर डेटा पुश करता है और दूसरा चैनल से डेटा प्राप्त करता है। नीचे दिए गए प्रोग्राम को देखें
package main import "fmt" import "time" //This subroutine pushes numbers 0 to 9 to the channel and closes the channel func add_to_channel(ch chan int) { fmt.Println("Send data") for i:=0; i<10; i++ { ch <- i //pushing data to channel } close(ch) //closing the channel } //This subroutine fetches data from the channel and prints it. func fetch_from_channel(ch chan int) { fmt.Println("Read data") for { //fetch data from channel x, flag := <- ch //flag is true if data is received from the channel //flag is false when the channel is closed if flag == true { fmt.Println(x) }else{ fmt.Println("Empty channel") break } } } func main() { //creating a channel variable to transport integer values ch := make(chan int) //invoking the subroutines to add and fetch from the channel //These routines execute simultaneously go add_to_channel(ch) go fetch_from_channel(ch) //delay is to prevent the exiting of main() before goroutines finish time.Sleep(5 * time.Second) fmt.Println("Inside main()") }
यहाँ 2 सबरूटीन हैं, एक चैनल पर डेटा पुश करता है और दूसरा चैनल पर डेटा प्रिंट करता है। add_to_channel फ़ंक्शन 0 से 9 तक की संख्याएँ जोड़ता है और चैनल को बंद कर देता है। साथ ही, fetch_from_channel फ़ंक्शन प्रतीक्षा करता है
x, flag := <- ch और जब डेटा उपलब्ध हो जाता है, तो यह डेटा प्रिंट करता है। जब फ्लैग गलत होता है, तो यह बाहर निकल जाता है, जिसका मतलब है कि चैनल बंद हो गया है।
main() में प्रतीक्षा का समय main() को तब तक बाहर जाने से रोकने के लिए दिया गया है जब तक कि गोरूटीन अपना निष्पादन पूरा नहीं कर लेता।
कोड निष्पादित करें और आउटपुट देखें
Read data Send data 0 1 2 3 4 5 6 7 8 9 Empty channel Inside main()
चुनते हैं
सेलेक्ट को स्विच स्टेटमेंट के रूप में देखा जा सकता है जो चैनलों पर काम करता है। यहाँ केस स्टेटमेंट एक चैनल ऑपरेशन होगा। आमतौर पर, प्रत्येक केस स्टेटमेंट को चैनल से पढ़ने का प्रयास किया जाएगा। जब कोई भी केस तैयार होता है (चैनल पढ़ा जाता है), तो उस केस से जुड़े स्टेटमेंट को निष्पादित किया जाता है। यदि कई केस तैयार हैं, तो यह एक यादृच्छिक केस चुनेगा। आपके पास एक डिफ़ॉल्ट केस हो सकता है जिसे तब निष्पादित किया जाता है जब कोई भी केस तैयार नहीं होता है।
आइये नीचे दिया गया कोड देखें
package main import "fmt" import "time" //push data to channel with a 4 second delay func data1(ch chan string) { time.Sleep(4 * time.Second) ch <- "from data1()" } //push data to channel with a 2 second delay func data2(ch chan string) { time.Sleep(2 * time.Second) ch <- "from data2()" } func main() { //creating channel variables for transporting string values chan1 := make(chan string) chan2 := make(chan string) //invoking the subroutines with channel variables go data1(chan1) go data2(chan2) //Both case statements wait for data in the chan1 or chan2. //chan2 gets data first since the delay is only 2 sec in data2(). //So the second case will execute and exits the select block select { case x := <-chan1: fmt.Println(x) case y := <-chan2: fmt.Println(y) } }
उपरोक्त प्रोग्राम को निष्पादित करने से निम्न आउटपुट प्राप्त होगा:
from data2()
यहाँ सेलेक्ट स्टेटमेंट किसी भी चैनल में डेटा उपलब्ध होने का इंतज़ार करता है। data2() 2 सेकंड की नींद के बाद चैनल में डेटा जोड़ता है जिससे दूसरा केस निष्पादित हो जाएगा।
उसी प्रोग्राम में सेलेक्ट में एक डिफ़ॉल्ट केस जोड़ें और आउटपुट देखें। यहाँ, सेलेक्ट ब्लॉक पर पहुँचने पर, यदि चैनल पर कोई भी केस डेटा तैयार नहीं है, तो यह किसी भी चैनल पर डेटा उपलब्ध होने की प्रतीक्षा किए बिना डिफ़ॉल्ट ब्लॉक को निष्पादित करेगा।
package main import "fmt" import "time" //push data to channel with a 4 second delay func data1(ch chan string) { time.Sleep(4 * time.Second) ch <- "from data1()" } //push data to channel with a 2 second delay func data2(ch chan string) { time.Sleep(2 * time.Second) ch <- "from data2()" } func main() { //creating channel variables for transporting string values chan1 := make(chan string) chan2 := make(chan string) //invoking the subroutines with channel variables go data1(chan1) go data2(chan2) //Both case statements check for data in chan1 or chan2. //But data is not available (both routines have a delay of 2 and 4 sec) //So the default block will be executed without waiting for data in channels. select { case x := <-chan1: fmt.Println(x) case y := <-chan2: fmt.Println(y) default: fmt.Println("Default case executed") } }
यह प्रोग्राम निम्न आउटपुट देगा:
Default case executed
ऐसा इसलिए है क्योंकि जब सेलेक्ट ब्लॉक पहुंचा, तो किसी भी चैनल के पास पढ़ने के लिए डेटा नहीं था। इसलिए, डिफ़ॉल्ट केस निष्पादित किया जाता है।
म्युटेक्स
म्यूटेक्स पारस्परिक बहिष्कार का संक्षिप्त रूप है। म्यूटेक्स का उपयोग तब किया जाता है जब आप किसी संसाधन को एक ही समय में कई सबरूटीन द्वारा एक्सेस करने की अनुमति नहीं देना चाहते हैं। म्यूटेक्स के 2 तरीके हैं - लॉक और अनलॉक। म्यूटेक्स सिंक पैकेज में समाहित है। इसलिए, आपको सिंक पैकेज को आयात करना होगा। जिन कथनों को पारस्परिक रूप से अनन्य रूप से निष्पादित किया जाना है, उन्हें mutex.Lock() और mutex.Unlock() के अंदर रखा जा सकता है।
आइए म्यूटेक्स को एक उदाहरण से सीखें जो लूप के निष्पादित होने की संख्या की गणना करता है। इस प्रोग्राम में हम उम्मीद करते हैं कि रूटीन 10 बार लूप चलाएगा और गिनती योग में संग्रहीत की जाती है। आप इस रूटीन को 3 बार कॉल करते हैं, इसलिए कुल गिनती 30 होनी चाहिए। गिनती एक वैश्विक चर गिनती में संग्रहीत है।
सबसे पहले, आप प्रोग्राम को बिना म्यूटेक्स के चलाएं
package main import "fmt" import "time" import "strconv" import "math/rand" //declare count variable, which is accessed by all the routine instances var count = 0 //copies count to temp, do some processing(increment) and store back to count //random delay is added between reading and writing of count variable func process(n int) { //loop incrementing the count by 10 for i := 0; i < 10; i++ { time.Sleep(time.Duration(rand.Int31n(2)) * time.Second) temp := count temp++ time.Sleep(time.Duration(rand.Int31n(2)) * time.Second) count = temp } fmt.Println("Count after i="+strconv.Itoa(n)+" Count:", strconv.Itoa(count)) } func main() { //loop calling the process() 3 times for i := 1; i < 4; i++ { go process(i) } //delay to wait for the routines to complete time.Sleep(25 * time.Second) fmt.Println("Final Count:", count) }
परिणाम देखें
Count after i=1 Count: 11 Count after i=3 Count: 12 Count after i=2 Count: 13 Final Count: 13
जब आप इसे निष्पादित करेंगे तो परिणाम भिन्न हो सकता है लेकिन अंतिम परिणाम 30 नहीं होगा।
यहाँ क्या होता है कि 3 गोरूटीन चर गिनती में संग्रहीत लूप गिनती को बढ़ाने की कोशिश कर रहे हैं। मान लीजिए कि एक पल में गिनती 5 है और गोरूटीन 1 गिनती को 6 तक बढ़ाने जा रहा है। मुख्य चरणों में शामिल हैं
गिनती को अस्थायी रूप से कॉपी करें
तापमान बढ़ाएँ
स्टोर का तापमान वापस गिनती पर
मान लीजिए कि गोरूटीन3 द्वारा चरण 1 निष्पादित करने के तुरंत बाद; दूसरे गोरूटीन में पुराना मान हो सकता है, मान लीजिए 3 उपरोक्त चरण करता है और 4 को वापस संग्रहीत करता है, जो गलत है। म्यूटेक्स का उपयोग करके इसे रोका जा सकता है, जो अन्य रूटीन को प्रतीक्षा करने का कारण बनता है जब एक रूटीन पहले से ही चर का उपयोग कर रहा होता है।
अब आप म्यूटेक्स के साथ प्रोग्राम चलाएँगे। यहाँ ऊपर बताए गए 3 चरण म्यूटेक्स में निष्पादित किए जाते हैं।
package main import "fmt" import "time" import "sync" import "strconv" import "math/rand" //declare a mutex instance var mu sync.Mutex //declare count variable, which is accessed by all the routine instances var count = 0 //copies count to temp, do some processing(increment) and store back to count //random delay is added between reading and writing of count variable func process(n int) { //loop incrementing the count by 10 for i := 0; i < 10; i++ { time.Sleep(time.Duration(rand.Int31n(2)) * time.Second) //lock starts here mu.Lock() temp := count temp++ time.Sleep(time.Duration(rand.Int31n(2)) * time.Second) count = temp //lock ends here mu.Unlock() } fmt.Println("Count after i="+strconv.Itoa(n)+" Count:", strconv.Itoa(count)) } func main() { //loop calling the process() 3 times for i := 1; i < 4; i++ { go process(i) } //delay to wait for the routines to complete time.Sleep(25 * time.Second) fmt.Println("Final Count:", count) }
अब आउटपुट होगा
Count after i=3 Count: 21 Count after i=2 Count: 28 Count after i=1 Count: 30 Final Count: 30
यहाँ हमें अंतिम आउटपुट के रूप में अपेक्षित परिणाम मिलता है। क्योंकि कथनों को पढ़ना, बढ़ाना और गिनती को वापस लिखना म्यूटेक्स में निष्पादित किया जाता है।
गलती संभालना
त्रुटियाँ असामान्य स्थितियाँ हैं जैसे किसी फ़ाइल को बंद करना जो खुली नहीं है, किसी फ़ाइल को खोलना जो मौजूद नहीं है, आदि। फ़ंक्शन आमतौर पर अंतिम रिटर्न मान के रूप में त्रुटियाँ लौटाते हैं।
नीचे दिया गया उदाहरण त्रुटि के बारे में अधिक बताता है।
package main import "fmt" import "os" //function accepts a filename and tries to open it. func fileopen(name string) { f, er := os.Open(name) //er will be nil if the file exists else it returns an error object if er != nil { fmt.Println(er) return }else{ fmt.Println("file opened", f.Name()) } } func main() { fileopen("invalid.txt") }
उत्पादन हो जाएगा:
open /invalid.txt: no such file or directory
यहाँ हमने एक गैर-मौजूद फ़ाइल को खोलने की कोशिश की, और इसने er variable में त्रुटि लौटा दी। यदि फ़ाइल वैध है, तो त्रुटि शून्य होगी
कस्टम त्रुटियाँ
इस सुविधा का उपयोग करके, आप कस्टम त्रुटियाँ बना सकते हैं। यह error पैकेज के New() का उपयोग करके किया जाता है। हम कस्टम त्रुटियों का उपयोग करने के लिए उपरोक्त प्रोग्राम को फिर से लिखेंगे।
नीचे दिया गया प्रोग्राम चलाएँ
package main import "fmt" import "os" import "errors" //function accepts a filename and tries to open it. func fileopen(name string) (string, error) { f, er := os.Open(name) //er will be nil if the file exists else it returns an error object if er != nil { //created a new error object and returns it return "", errors.New("Custom error message: File name is wrong") }else{ return f.Name(),nil } } func main() { //receives custom error or nil after trying to open the file filename, error := fileopen("invalid.txt") if error != nil { fmt.Println(error) }else{ fmt.Println("file opened", filename) } }
उत्पादन हो जाएगा:
Custom error message:File name is wrong
यहाँ area() वर्ग का क्षेत्रफल लौटाता है। यदि इनपुट 1 से कम है तो area() एक त्रुटि संदेश लौटाता है।
फाइलें पढ़ना
फ़ाइलों का उपयोग डेटा संग्रहीत करने के लिए किया जाता है। Go हमें फ़ाइलों से डेटा पढ़ने की अनुमति देता है
सबसे पहले अपनी वर्तमान निर्देशिका में नीचे दी गई सामग्री के साथ एक फ़ाइल, data.txt, बनाएँ।
Line one Line two Line three
अब नीचे दिए गए प्रोग्राम को चलाकर देखें कि यह संपूर्ण फ़ाइल की सामग्री को आउटपुट के रूप में प्रिंट करता है
package main import "fmt" import "io/ioutil" func main() { data, err := ioutil.ReadFile("data.txt") if err != nil { fmt.Println("File reading error", err) return } fmt.Println("Contents of file:", string(data)) }
यहाँ डेटा, err := ioutil.ReadFile(“data.txt”) डेटा को पढ़ता है और एक बाइट अनुक्रम लौटाता है। प्रिंट करते समय इसे स्ट्रिंग प्रारूप में परिवर्तित किया जाता है।
फ़ाइलें लिखना
आप इसे एक प्रोग्राम के साथ देखेंगे
package main import "fmt" import "os" func main() { f, err := os.Create("file1.txt") if err != nil { fmt.Println(err) return } l, err := f.WriteString("Write Line one") if err != nil { fmt.Println(err) f.Close() return } fmt.Println(l, "bytes written") err = f.Close() if err != nil { fmt.Println(err) return } }
यहाँ एक फ़ाइल बनाई जाती है, test.txt. अगर फ़ाइल पहले से मौजूद है तो फ़ाइल की सामग्री को छोटा कर दिया जाता है। फ़ाइल में सामग्री लिखने के लिए Writeline() का उपयोग किया जाता है। उसके बाद, आप Close() का उपयोग करके फ़ाइल को बंद कर देते हैं।
धोखा की चादर
इस गो ट्यूटोरियल में, हमने कवर किया,
विषय | विवरण | वाक्य - विन्यास |
---|---|---|
मूल प्रकार | संख्यात्मक, स्ट्रिंग, बूल | |
चर | चरों को मान घोषित करें और असाइन करें | var variable_name प्रकार var variable_name प्रकार = मान var variable_name1, variable_name2 = value1, value2 variable_name := मान |
स्थिरांक | वे चर जिनका मान एक बार निर्दिष्ट होने के बाद बदला नहीं जा सकता | स्थिर चर = मान |
पाश के लिए | कथनों को लूप में निष्पादित करें. | प्रारंभिक_अभिव्यक्ति; मूल्यांकन_अभिव्यक्ति; पुनरावृत्ति_अभिव्यक्ति के लिए{ // एक या अधिक कथन } |
यदि अन्यथा | यह एक सशर्त कथन है | अगर शर्त{ // कथन_1 और} { // कथन_2 } |
स्विच | अनेक मामलों के साथ सशर्त कथन | स्विच अभिव्यक्ति { केस मान_1: कथन_1 केस मान_2: कथन_2 केस value_n: कथन_n चूक: कथन_डिफ़ॉल्ट } |
ऐरे | समान प्रकार के तत्वों का निश्चित आकार नामित अनुक्रम | arrayname := [आकार] प्रकार {value_0,value_1,…,value_size-1} |
टुकड़ा | किसी सारणी का भाग या खंड | var स्लाइस_नाम [] प्रकार = array_name[प्रारंभ:अंत] |
कार्य | कथनों का ब्लॉक जो एक विशिष्ट कार्य करता है | func फ़ंक्शन_नाम(पैरामीटर_1 प्रकार, पैरामीटर_n प्रकार) return_type { //कथन } |
संकुल | कोड को व्यवस्थित करने के लिए उपयोग किया जाता है। कोड की पठनीयता और पुनः प्रयोज्यता को बढ़ाता है | पैकेज_नाम आयात करें |
आस्थगित करें | किसी फ़ंक्शन के निष्पादन को तब तक स्थगित करता है जब तक कि उसमें शामिल फ़ंक्शन का निष्पादन समाप्त नहीं हो जाता | स्थगित फ़ंक्शन_नाम(पैरामीटर_सूची) |
संकेत | किसी अन्य चर का मेमोरी पता संग्रहीत करता है. | var variable_name *प्रकार |
संरचना | उपयोगकर्ता द्वारा परिभाषित डेटा प्रकार जिसमें स्वयं समान या भिन्न प्रकार का एक और तत्व शामिल होता है | प्रकार संरचनानाम संरचना { variable_1 variable_1_type variable_2 variable_2_type variable_n variable_n_type } |
तरीके | विधि एक रिसीवर तर्क वाला फ़ंक्शन है | func (चर variabletype) methodName(पैरामीटर_सूची) { } |
गोरौटाइन | एक फ़ंक्शन जो अन्य फ़ंक्शनों के साथ समवर्ती रूप से चल सकता है। | फ़ंक्शन_नाम(पैरामीटर_सूची) पर जाएँ |
चैनल | कार्यों के लिए एक दूसरे से संवाद करने का तरीका। एक माध्यम जिसके द्वारा एक रूटीन डेटा रखता है और जिसे दूसरे रूटीन द्वारा एक्सेस किया जाता है। | घोषित: ch := make(चैन int) चैनल को डेटा भेजें: चैनल_चर <- चर_नाम चैनल से प्राप्त करें: variable_name := <- चैनल_चर |
चुनते हैं | स्विच स्टेटमेंट जो चैनल पर काम करता है। केस स्टेटमेंट एक चैनल ऑपरेशन होगा। जब कोई भी चैनल डेटा के साथ तैयार होता है, तो उस केस से जुड़े स्टेटमेंट को निष्पादित किया जाता है | चुनना { केस x := <-chan1: fmt.प्रिंटलाइन(x) केस y := <-chan2: fmt.प्रिंटलाइन(y) } |
म्युटेक्स | म्यूटेक्स का उपयोग तब किया जाता है जब आप किसी संसाधन को एक ही समय में कई सबरूटीन द्वारा एक्सेस करने की अनुमति नहीं देना चाहते हैं। म्यूटेक्स के 2 तरीके हैं - लॉक और अनलॉक | म्यूटेक्स.लॉक() //कथन म्यूटेक्स.अनलॉक(). |
फ़ाइलें पढ़ें | डेटा को पढ़ता है और बाइट अनुक्रम लौटाता है। | डेटा, त्रुटि := ioutil.ReadFile(फ़ाइलनाम) |
फ़ाइल लिखें | डेटा को फ़ाइल में लिखता है | l, त्रुटि := f.WriteString(text_to_write) |