गो HTTP हैंडलर्स में, ResponseWriter का मान क्यों होता है, लेकिन रिक्वेस्ट पॉइंटर?


84

मैं GAE के लिए एक ऐप लिखकर Go सीख रहा हूं, और यह एक हैंडलर फ़ंक्शन का हस्ताक्षर है:

func handle(w http.ResponseWriter, r *http.Request) {}

मैं यहाँ पॉइंटर नौसिखिया हूँ, इसलिए Requestऑब्जेक्ट पॉइंटर क्यों है , लेकिन ResponseWriterनहीं? क्या इस तरह से इसे करने की कोई आवश्यकता है या यह केवल कुछ प्रकार के उन्नत सूचक आधारित कोड को संभव बनाने के लिए है?

जवाबों:


66

आपको जो कुछ भी मिलता wहै वह गैर-निर्यात प्रकार के लिए एक संकेतक है http.responseलेकिन जैसा ResponseWriterकि एक इंटरफ़ेस है, यह दिखाई नहीं देता है।

से server.go :

type ResponseWriter interface {
    ...
}

दूसरी ओर, rएक ठोस संरचना का सूचक है, इसलिए एक संदर्भ को स्पष्ट रूप से पारित करने की आवश्यकता है।

से request.go :

type Request struct {
    ...
}

28

http.ResponseWriterएक इंटरफेस है, और इस इंटरफेस को लागू करने मौजूदा प्रकार संकेत दिए गए हैं। इसका मतलब है कि इस इंटरफ़ेस को पॉइंटर का उपयोग करने की कोई आवश्यकता नहीं है, क्योंकि यह पहले से ही एक पॉइंटर द्वारा "समर्थित" है। यह अवधारणा यहाँ जाने वाले डेवेलपर्स में से एक द्वारा थोड़ा सा वर्णन की गई है, हालाँकि http.ResponseWriter को लागू करने वाले एक प्रकार को पॉइंटर होने की आवश्यकता नहीं है, यह व्यावहारिक नहीं होगा, कम से कम गो http सर्वर के भीतर नहीं।

http.Requestएक इंटरफ़ेस नहीं है, यह सिर्फ एक संरचना है, और चूंकि हम इस संरचना को बदलना चाहते हैं और वेब सर्वर को उन परिवर्तनों को देखना है, इसलिए इसे एक सूचक होना चाहिए। यदि यह केवल एक संरचनात्मक मूल्य था, तो हम इसकी एक प्रति को संशोधित करेंगे जो हमारे कोड को कॉल करने वाला वेब सर्वर नहीं देख सकता था।


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

2
खैर, मेरा मतलब यह नहीं था कि इंटरफ़ेस को लागू करने वाली सभी चीजों को इंगित करना होगा। एक ResponseWriter की तरह कुछ जो उपयोगी कुछ भी करने के लिए इंटरफ़ेस के पीछे के मूल्य की स्थिति को संशोधित करने की आवश्यकता होगी, और इसके लिए उस मूल्य की आवश्यकता होगी जो एक पॉइंटर प्रकार है (जैसा कि ब्लॉग पोस्ट मैं भी कहता हूं)। लेकिन हाँ, http.ResponseWriter सैद्धांतिक रूप से एक int (जिसका तरीका कभी भी उस int value को बदल नहीं सकता) द्वारा कार्यान्वित किया जा सकता है।
ओपन स्कूल

यह उत्तर सुपर सहायक था। यह लिंक अनमोल है, हम में से उन लोगों के लिए स्पष्ट स्पष्टीकरण के साथ नया संकेत है। "यह है, हालांकि कोई स्पष्ट मार्कर नहीं है, इंटरफ़ेस ऑब्जेक्ट अक्सर पॉइंटर्स की तरह काम करते हैं। यह तब तक भ्रामक हो सकता है जब तक आप समझते हैं कि वास्तव में क्या चल रहा है।"
कोडी Django

1
अनुरोध के बारे में हिस्सा वास्तव में गलत है, मेरा उत्तर देखें stackoverflow.com/a/56875204/989991
joakim

7

जैसा कि यहां और अन्य कई अन्य उत्तरों में सही ढंग से उल्लेख किया गया है, ResponseWriterएक इंटरफ़ेस है और इस के निहितार्थों का SO के उत्तर और ब्लॉग में विस्तार से वर्णन किया गया है ।

मैं जो कहना चाहता हूं, वह यह है कि जो मुझे लगता है वह बड़ा है और खतरनाक है- यहां गलत धारणा, कि कारण अनुरोध "संदर्भ" द्वारा पारित किया गया है (हालांकि ऐसी कोई चीज वास्तव में गो में मौजूद नहीं है ) यह है कि "हम बदलाव करना चाहते हैं यह सर्वर को दिखाई देता है "।

कुछ उत्तरों का उद्धरण:

[..] यह सिर्फ एक struct है, और जब से हमने यह struct बदल सकते हैं और वेब सर्वर उन परिवर्तनों को देखने करना चाहते हैं, यह एक सूचक हो गया है [..] अतः

[..] अनुरोध करने के लिए हैंडलर जरूरत से सर्वर के लिए दिखाई दे सकता है, बदलता है तो हम बजाय केवल संदर्भ द्वारा इसे पारित कर रहे हैं मूल्य द्वारा [..] अतः

यह गलत है ; वास्तव में डॉक्स ने अनुरोध को छेड़छाड़ / छेड़छाड़ के खिलाफ स्पष्ट रूप से चेतावनी दी है :

शरीर को पढ़ने के अलावा, हैंडलर को प्रदान किए गए अनुरोध को संशोधित नहीं करना चाहिए।

इसके विपरीत, नहीं? :-)

यदि आप अनुरोध बदलना चाहते हैं, जैसे कि एक मिडलवेयर चेन में अगले हैंडलर पर जाने से पहले एक ट्रेसिंग हेडर को संलग्न करें, तो आपको अनुरोध को कॉपी करना होगा और कॉपी किए गए संस्करण को चेन से नीचे पारित करना होगा।

आने वाले अनुरोध के संशोधनों को अनुमति देने के लिए व्यवहार को बदलने का अनुरोध गो टीम के साथ उठाया गया है, लेकिन इस तरह से कुछ बदलने से शायद कम से कम कुछ मौजूदा कोड अप्रत्याशित रूप से टूट जाएंगे।

यदि हम स्पष्ट रूप से लोगों से अनुरोध को म्यूट न करने के लिए कह रहे हैं तो पॉइंटर का उपयोग क्यों करें? प्रदर्शन , Requestएक बड़ी संरचना है और इसे कॉपी करने से प्रदर्शन में गिरावट आ सकती है, खासकर लंबी मिडलवेयर चेन को ध्यान में रखकर। टीम को एक संतुलन बनाना था, निश्चित रूप से एक आदर्श समाधान नहीं था, लेकिन ट्रेडऑफ़ स्पष्ट रूप से यहां प्रदर्शन (एपीआई के बजाय) के पक्ष में हैं।


1
यह वह जवाब है जिसने आखिरकार मुझे समझ में आया।
जिमी

2

कारण यह अनुरोध करने के लिए एक सूचक सरल है: हैंडलर द्वारा अनुरोध करने के लिए परिवर्तन सर्वर को दिखाई देने की जरूरत है, इसलिए हम केवल मूल्य के बजाय संदर्भ द्वारा इसे पारित कर रहे हैं।

यदि आप नेट / http लाइब्रेरी कोड में खोदते हैं, तो आप पाएंगे कि ResponseWriter एक नोक्सपोर्टेड स्ट्रक्चर रिस्पॉन्स के लिए एक इंटरफेस है, और हम संदर्भ द्वारा स्ट्रक्चर को पास कर रहे हैं (हम रिस्पॉन्स के लिए पॉइंटर में गुजर रहे हैं) और वैल्यू से नहीं । ResponseWriter एक इंटरफ़ेस है जो एक हैंडलर HTTP प्रतिक्रिया बनाने के लिए उपयोग करता है। ResponseWriter का बैकअप लेने वाला वास्तविक स्ट्रक्चर कोई नहीं है। क्योंकि यह कोई नहीं है, आप इसे सीधे उपयोग नहीं कर सकते हैं; आप केवल ResponseWriter इंटरफ़ेस के माध्यम से इसका उपयोग कर सकते हैं।

दूसरे शब्दों में, दोनों मापदंडों को संदर्भ से पारित किया जाता है; यह सिर्फ इतना है कि विधि हस्ताक्षर एक ResponseWriter लेता है जो कि एक संरचना के लिए एक संकेतक के लिए एक इंटरफ़ेस है, इसलिए ऐसा लगता है जैसे कि यह मूल्य से पारित हो गया है।


मेरे मूल उत्तर की तुलना में अधिक समझ में आता है
वेंकट एसएसकेएम चैतन्य

अनुरोध के बारे में हिस्सा वास्तव में गलत है, मेरा उत्तर देखें stackoverflow.com/a/56875204/989991
joakim

0

मुझे लगता है कि Requestऑब्जेक्ट को पॉइंटर के रूप में पारित करने का मुख्य कारण Bodyफ़ील्ड है। किसी दिए गए HTTP अनुरोध के लिए, शरीर केवल एक बार पढ़ सकता है। यदि Requestऑब्जेक्ट को क्लोन किया गया था, जैसा कि यह होगा यदि यह एक पॉइंटर के रूप में पारित नहीं किया गया था, तो हमारे पास दो वस्तुएं होंगी जिनके बारे में अलग-अलग जानकारी है कि शरीर से कितना पढ़ा गया है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.