गोलांग कोडिंग मानक मूल दिशानिर्देश
संसाधनों को रिहा करने के लिए defer का प्रयोग करें
फ़ाइलें और लॉक जैसे संसाधनों को रिहा करने के लिए defer का प्रयोग करें।
अनुशंसित नहीं:
p.Lock()
if p.count < 10 {
p.Unlock()
return p.count
}
p.count++
newCount := p.count
p.Unlock()
// बयां विभिन्न वापसी शाखाओं में unlock भूलना आसान हो जाता है
अनुशंसित:
p.Lock()
defer p.Unlock()
if p.count < 10 {
return p.count
}
p.count++
return p.count
// अधिक पठनीय
डिफर का ओवरहेड अत्यंत कम है, इसलिए इसे नकारते हैं जब आप सिद्ध कर सकते हैं कि फ़ंक्शन का क्रियान्वयन समय नैनोसेकंड स्तर पर है। पठनीयता में सुधार के लिए डिफर का प्रयोग करना योग्य है क्योंकि इनका उपयोग करने का खर्च अनदेखा है। यह विशेष रूप से बड़े विधियों के लिए लागू होता है जिनमें केवल साधारण मेमोरी एक्सेस से अधिक कैलकुलेशन की संसाधन सेवना होती है, जिनकी खपत डिफर की कीमत से अधिक होती है।
चैनल का आकार 1 या अनबफर्ड होना चाहिए
चैनल का आम रूप से 1 या अनबफर्ड होना चाहिए। डिफ़ॉल्ट रूप से, चैनल अनबफर्ड होते हैं और उनका आकार शून्य होता है। किसी भी अन्य आकार को सख्ती से समीक्षा करना चाहिए। हमें यह सोचना चाहिए कि आकार कैसे निर्धारित करें, चैनल को उच्च लोड के तहत लिखना कैसे रोकता है और बंद होने पर क्या परिवर्तन प्रणाली लॉजिक में होता है।
अनुशंसित नहीं:
// किसी स्थिति को संभालने के लिए पर्याप्त होना चाहिए!
c := make(chan int, 64)
अनुशंसित:
// आकार: 1
c := make(chan int, 1) // या
// अनबफर्ड चैनल, आकार शून्य है
c := make(chan int)
ईनुम 1 से शुरू होना चाहिए
गो में ईनुम को प्रस्तुत करने का मानक तरीका एक कस्टम प्रकार और आइयोटा का प्रयोग करना है। क्योंकि वेरिएबल की डिफ़ॉल्ट मान 0 होती है, ईनुम को सामान्यत: गैर-शून्य मान से शुरू होना चाहिए।
अनुशंसित नहीं:
type Operation int
const (
Add Operation = iota
Subtract
Multiply
)
// Add=0, Subtract=1, Multiply=2
अनुशंसित:
type Operation int
const (
Add Operation = iota + 1
Subtract
Multiply
)
// Add=1, Subtract=2, Multiply=3
कुछ मामलों में, शून्य मान का प्रयोग समझदारी है (जो शून्य से आरंभ होता है), उदाहरण के लिए, जब शून्य मान आदर्श डिफ़ॉल्ट व्यवहार होता है।
type LogOutput int
const (
LogToStdout LogOutput = iota
LogToFile
LogToRemote
)
// LogToStdout=0, LogToFile=1, LogToRemote=2
एटॉमिक का प्रयोग
मूल टाइप्स (int32
, int64
, आदि) पर कार्य करने के लिए sync/atomic पैकेज से एटॉमिक कार्यों का प्रयोग करें क्योंकि वेरियबल्स से पठन या संशोधन करने को भूलना आसान है।
go.uber.org/atomic से इन कार्यों में टाइप सेफ़ता जोड़ी जाती है और इसके अंतर्गत एक सुरक्षित atomic.Bool
टाइप भी शामिल है।
अनुशंसित नहीं:
type foo struct {
running int32 // atomic
}
func (f* foo) start() {
if atomic.SwapInt32(&f.running, 1) == 1 {
// पहले से चल रहा है…
return
}
// Foo को शुरू करें
}
func (f *foo) isRunning() bool {
return f.running == 1 // race!
}
अनुशंसित:
type foo struct {
running atomic.Bool
}
func (f *foo) start() {
if f.running.Swap(true) {
// पहले से चल रहा है…
return
}
// Foo को शुरू करें
}
func (f *foo) isRunning() bool {
return f.running.Load()
}
परिवर्तनशील ग्लोबल चरों से बचें
ग्लोबल चरों को बदलने से बचने के लिए विभारण संज्ञान का उपयोग करें। यह सम्मानित है एक्सन के पॉइंटर और अन्य मूल्य प्रकारों के लिए।
अनुशंसित उपाय 1:
// sign.go
var _timeNow = time.Now
func sign(msg string) string {
now := _timeNow()
return signWithTime(msg, now)
}
सारांशिक उपाय 1:
// sign.go
type signer struct {
now func() time.Time
}
func newSigner() *signer {
return &signer{
now: time.Now,
}
}
func (s *signer) Sign(msg string) string {
now := s.now()
return signWithTime(msg, now)
}
अनुशंसित उपाय 2:
// sign_test.go
func TestSign(t *testing.T) {
oldTimeNow := _timeNow
_timeNow = func() time.Time {
return someFixedTime
}
defer func() { _timeNow = oldTimeNow }()
assert.Equal(t, want, sign(give))
}
सारांशित उपाय 2:
// sign_test.go
func TestSigner(t *testing.T) {
s := newSigner()
s.now = func() time.Time {
return someFixedTime
}
assert.Equal(t, want, s.Sign(give))
}
पूर्व-निर्धारित पहचानकर्ताओं का उपयोग न करें
गो भाषा विनिर्देश में कई पहले से निर्धारित पहचानकर्ता दिये गये हैं जो गो परियोजनाओं में उपयोग नहीं करना चाहिए। इन पहले से निर्धारित पहचानकर्ताओं का पुन:उपयोग विभिन्न संदर्भों में नहीं किया जाना चाहिए, क्योंकि ऐसा करने से वर्तमान दृश्य परिवेश में मूल पहचानकर्ताओं को छिपा सकता है (या किसी भी घेरे हुए परिवेश में), संभावनात: कोड भ्रम का कारण बन सकता है। सर्वश्रेष्ठ मामले में, कंपाइलर त्रुटि उठाएगा; अत्यंत मामले में, ऐसा कोड नुकसानप्रद, मुश्किल से पुनःप्राप्त त्रुटियां दर्ज कर सकता है।
अनुशंसित अभ्यास 1:
var error string
// `error` स्वतः बनाये गए पहचानकर्ता को छिपाता है
// या
func handleErrorMessage(error string) {
// `error` स्वतः बनाये गए पहचानकर्ता को छिपाता है
}
सारांशित अभ्यास 1:
var errorMessage string
// `error` अब मूल पहचानकर्ता के लिए है
// या
func handleErrorMessage(msg string) {
// `error` अब मूल पहचानकर्ता के लिए है
}
अनुशंसित अभ्यास 2:
type Foo struct {
// यद्यपि ये क्षेत्र सावधानीपूर्वक छिपे नहीं हैं, फिर भी `error` या `string` स्ट्रिंग अब अस्पष्ट हो जाती हैं।
error error
string string
}
func (f Foo) Error() error {
// `error` और `f.error` के रूप में दृश्य में समान दीखते हैं
return f.error
}
func (f Foo) String() string {
// `string` और `f.string` के रूप में दृश्य में समान दीखते हैं
return f.string
}
सारांशित अभ्यास 2:
type Foo struct {
// `error` और `string` अब स्पष्ट हैं।
err error
str string
}
func (f Foo) Error() error {
return f.err
}
func (f Foo) String() string {
return f.str
}
ध्यान दें कि कंपाइलर पहले से निर्धारित पहचानकर्ताओं का उपयोग करते समय त्रुटियों को उत्पन्न नहीं करेगा, लेकिन go vet
जैसे उपकरण सही तरीके से इन और संबद्ध परिस्थितियों को निश्चित करेगा।
init()
का उपयोग न करें
init()
का उपयोग हो सकने पर संभावना होती है, लेकिन इसका प्रयोग अमान्य होने पर या पसंद होने पर उपयोग करने के लिए कोड को निम्नलिखित का पालन करना चाहिए:
- कार्यक्रम वातावरण या कॉल के बावजूद पूर्णता सुनिश्चित करें।
- अन्य
init()
के क्रम या सहारित प्रभावों पर निर्भर करने से बचें। हालांकि,init()
के क्रम को स्पष्ट किया गया है, कोड बदल सकता है, इसलिएinit()
के क्रम के बीच संबंध कोड को कमजोर और त्रुटि प्रोन बना सकता है। - मशीन सूचन, पर्यावरणीय चर, काम करने वाले निर्देशक, कार्यक्रम पैरामीटर/इनपुट आदि जैसी ग्लोबल या पर्यावरणीय संदीप्तियों या स्थितियों को पहुंचने या परिवर्तित करने से बचें।
- फाइल सिस्टम, नेटवर्किंग, और सिस्टम कॉल जैसी I/O से बचें।
इन मापदंडों को पूरा न करने वाला कोड या मैन() कॉल (या कार्यक्रम की जीवनचक्र में कहीं और) का हिस्सा हो सकता है या फिर उसे अपने आप मैं() के रूप में लिखा जा सकता है। विशेष रूप से, अन्य प्रोग्रामों द्वारा उपयोग के लिए निर्माणित पुस्तकालयों को सम्पूर्णता पर विशेष ध्यान दिया जाना चाहिए कि वे "प्रारंभिक भौतिकी" की बजाय संकेतक रूप से पूर्णता पर ध्यान दें।
असंशोधित तरीका 1:
type Foo struct {
// ...
}
var _defaultFoo Foo
func init() {
_defaultFoo = Foo{
// ...
}
}
पसंदीदा तरीका 1:
var _defaultFoo = Foo{
// ...
}
// या, परीक्षण के लिए बेहतर:
var _defaultFoo = defaultFoo()
func defaultFoo() Foo {
return Foo{
// ...
}
}
असंशोधित तरीका 2:
type Config struct {
// ...
}
var _config Config
func init() {
// खराब: वर्तमान निर्देशिका के आधार पर
cwd, _ := os.Getwd()
// खराब: I/O
raw, _ := os.ReadFile(
path.Join(cwd, "config", "config.yaml"),
)
yaml.Unmarshal(raw, &_config)
}
पसंदीदा तरीका 2:
type Config struct {
// ...
}
func loadConfig() Config {
cwd, err := os.Getwd()
// त्रुटि का संबंध बनाए रखें
raw, err := os.ReadFile(
path.Join(cwd, "config", "config.yaml"),
)
// त्रुटि का संबंध बनाए रखें
var config Config
yaml.Unmarshal(raw, &config)
return config
}
उपरोक्त विचारों के अनुसार, कुछ मामलों में init()
का उपयोग अधिक पसंदीदा या आवश्यक हो सकता है, जैसे:
- एक संयोजन व्यक्ति की एकल भव्य अभिव्यक्ति के रूप में प्रस्तुत नहीं किया जा सकता है।
-
database/sql
, प्रकार रजिस्ट्री आदि जैसे इंजेक्टेबल हुक ।
जोड़ने के लिए स्लाइस क्षमता का निर्दिष्ट करना पसंद करें
स्लाइस को जोड़ने के लिए make()
के लिए एक क्षमता मूल्य का प्राथमिकता दें।
असम्भावित उपाय:
for n := 0; n < b.N; n++ {
data := make([]int, 0)
for k := 0; k < size; k++{
data = append(data, k)
}
}
पसंदीदा उपाय:
for n := 0; n < b.N; n++ {
data := make([]int, 0, size)
for k := 0; k < size; k++{
data = append(data, k)
}
}
संरचना सीरीकरण में फील्ड टैग का उपयोग
JSON, YAML, या किसी और संरचना के लिए फ़ील्ड नाम आधारित अनुक्रमण में सीरीकरण करते समय, संबंधित टैग का उपयोग अवगति के लिए किया जाना चाहिए।
अमान्य उपाय:
type Stock struct {
Price int
Name string
}
bytes, err := json.Marshal(Stock{
Price: 137,
Name: "UBER",
})
पसंदीदा उपाय:
type Stock struct {
Price int `json:"price"`
Name string `json:"name"`
// नाम को सिंबोल में बदलना सुरक्षित है।
}
bytes, err := json.Marshal(Stock{
Price: 137,
Name: "UBER",
})
सिद्धांतिक रूप से, संरचना के सीरीकरण प्रारूप को विभिन्न प्रणालियों के बीच एक समझौते होता है। इसे बिना अनुबंधों में फिल्ड नामों में परिवर्तन करना इस समझौते को तोड़ देगा। टैग में फिल्ड नाम निर्दिष्ट करना समझौते को स्पष्ट बनाता है और भ्रमित करने से बचाता है, अनुक्रमण या फिल्ड के नाम को प्रारूपात्मक के माध्यम से भंग करने के द्वारा संधित संधि के अकसरी उल्लंघन को रोकता है।