मुझे सी # बिल्कुल पता नहीं है, इसलिए सी # के बारे में जो कुछ भी मैं कहता हूं उसे नमक के अनाज से लिया जाना चाहिए। हालांकि, मैं यह समझाने की कोशिश करूंगा कि रुबी कोड के उस टुकड़े में क्या चल रहा है।
class << Cache
रूबी कुछ सिंगलटन तरीकों कहा जाता है। इन्हें सिंगलटन सॉफ्टवेयर डिजाइन पैटर्न से कोई लेना देना नहीं है, वे केवल वे विधियां हैं जिन्हें एक और केवल एक ऑब्जेक्ट के लिए परिभाषित किया गया है। तो, आपके पास एक ही कक्षा के दो उदाहरण हो सकते हैं, और उन दो वस्तुओं में से एक में विधियां जोड़ सकते हैं।
सिंगलटन विधियों के लिए दो अलग-अलग वाक्यविन्यास हैं। एक ऑब्जेक्ट के साथ विधि के नाम को बस उपसर्ग करना है, इसलिए def foo.bar(baz)
केवल foo
ऑब्जेक्ट के लिए bar
विधि को परिभाषित करेगा। दूसरी विधि को कहा जाता है जिसे सिंगलटन क्लास खोलना पड़ता है और यह कक्षा को परिभाषित करने के लिए वाक्य रचनात्मक रूप से समान दिखता है, क्योंकि यह भी अर्थात् होता है: सिंगलटन विधियां वास्तव में एक अदृश्य कक्षा में रहती हैं जो कक्षा में वस्तु और उसके वास्तविक वर्ग के बीच डाली जाती है पदानुक्रम।
यह वाक्यविन्यास इस तरह दिखता है: class << foo
। यह ऑब्जेक्ट foo
की सिंगलटन क्लास खोलता है और उस वर्ग निकाय के अंदर परिभाषित हर विधि ऑब्जेक्ट foo
ऑब्जेक्ट की सिंगलटन विधि बन जाती है।
इसका उपयोग क्यों किया जाता है? खैर, रूबी एक शुद्ध ऑब्जेक्ट उन्मुख भाषा है, जिसका अर्थ है कि सब कुछ, कक्षाओं सहित एक वस्तु है। अब, यदि अलग-अलग वस्तुओं में विधियों को जोड़ा जा सकता है, और कक्षाएं वस्तुएं हैं, तो इसका मतलब है कि अलग-अलग वर्गों में विधियों को जोड़ा जा सकता है। दूसरे शब्दों में, रूबी को नियमित तरीकों और स्थैतिक तरीकों के बीच कृत्रिम भेद की आवश्यकता नहीं है (जो धोखाधड़ी है, वैसे भी: वे वास्तव में विधियां नहीं हैं, केवल गौरव प्रक्रियाएं हैं)। सी # में एक स्थिर विधि क्या है, क्लास ऑब्जेक्ट की सिंगलटन कक्षा पर केवल एक नियमित विधि है।
यह सब कुछ समझाने का एक लंबा तरीका है कि class << Cache
और इसके संबंधित end
के बीच परिभाषित सब कुछ static
बन गया है।
STALE_REFRESH = 1
STALE_CREATED = 2
रुबी में, प्रत्येक चर जो पूंजी पत्र से शुरू होता है, वास्तव में एक स्थिर है। हालांकि, इस मामले में हम इन्हें static const
फ़ील्ड के रूप में अनुवाद नहीं करेंगे, बल्कि enum
, क्योंकि इस तरह उनका उपयोग किया जाता है।
# Caches data received from a block
#
# The difference between this method and usual Cache.get
# is following: this method caches data and allows user
# to re-generate data when it is expired w/o running
# data generation code more than once so dog-pile effect
# won't bring our servers down
#
def smart_get(key, ttl = nil, generation_time = 30.seconds)
इस विधि (वास्तव में चार, हम वास्तव में देखेंगे क्यों बाद में) तीन पैरामीटर है, उनमें से दो वैकल्पिक (ttl
और generation_time
) कर रहे हैं। उनमें से दोनों का डिफ़ॉल्ट मान है, हालांकि, ttl
के मामले में डिफ़ॉल्ट मान वास्तव में उपयोग नहीं किया जाता है, यह यह जानने के लिए मार्कर के रूप में अधिक कार्य करता है कि तर्क पारित किया गया था या नहीं।
30.seconds
एक विस्तार है कि ActiveSupport
लाइब्रेरी Integer
कक्षा में जोड़ती है। यह वास्तव में कुछ भी नहीं करता है, यह सिर्फ self
देता है। इस मामले में विधि विधि परिभाषा को अधिक पठनीय बनाने के लिए प्रयोग किया जाता है। (अन्य विधियां हैं जो कुछ और उपयोगी बनाती हैं, उदाहरण के लिए Integer#minutes
, जो self * 60
और Integer#hours
और इसी तरह से लौटाती है।) हम इसे एक संकेत के रूप में उपयोग करेंगे, कि पैरामीटर का प्रकार int
नहीं बल्कि System.TimeSpan
होना चाहिए।
# Fallback to default caching approach if no ttl given
return get(key) { yield } unless ttl
इसमें कई जटिल रूबी संरचनाएं हैं। आइए सबसे आसान से शुरू करें: पीछे सशर्त संशोधक। यदि एक सशर्त निकाय में केवल एक अभिव्यक्ति होती है, तो सशर्त अभिव्यक्ति के अंत में जोड़ा जा सकता है। तो, if a > b then foo end
कहने के बजाय आप foo if a > b
भी कह सकते हैं। तो, उपरोक्त unless ttl then return get(key) { yield } end
के बराबर है।
अगला वाला भी आसान है: unless
if not
के लिए सिंटैक्टिक चीनी है। तो, अब हम if not ttl then return get(key) { yield } end
तीसरे रूबी की सच्ची प्रणाली है। रूबी में, सच बहुत सरल है। दरअसल, झूठापन बहुत सरल है, और सच्चाई स्वाभाविक रूप से बाहर आती है: विशेष कीवर्ड false
गलत है, और विशेष कीवर्ड nil
गलत है, बाकी सब कुछ सच है। तो, इस मामले में सशर्त केवल सत्य हो, यदि ttl
या तो false
या nil
है। false
एक समय के लिए एक भयानक समझदार मूल्य नहीं है, इसलिए केवल दिलचस्प एक nil
है। स्निपेट इस तरह अधिक स्पष्ट रूप से लिखा होगा: if ttl.nil? then return get(key) { yield } end
। चूंकि ttl
पैरामीटर के लिए डिफ़ॉल्ट मान nil
है, इसलिए यह सशर्त सत्य है, यदि ttl
के लिए कोई तर्क पारित नहीं हुआ है। इसलिए, सशर्त का उपयोग यह पता लगाने के लिए किया जाता है कि विधि को कितने तर्क कहा जाता था, जिसका अर्थ है कि हम इसे एक सशर्त के रूप में अनुवाद करने के लिए नहीं बल्कि एक विधि अधिभार के रूप में अनुवाद करने जा रहे हैं।
अब yield
पर। रुबी में, प्रत्येक विधि एक निहित कोड ब्लॉक को तर्क के रूप में स्वीकार कर सकती है। यही कारण है कि मैंने ऊपर लिखा है कि विधि वास्तव में चार तर्क लेती है, तीन नहीं। एक कोड ब्लॉक कोड का एक अज्ञात टुकड़ा है जिसे चारों ओर पारित किया जा सकता है, एक चर में संग्रहीत किया जाता है, और बाद में इसका आह्वान किया जाता है। रुबी को स्मॉलटाक से ब्लॉक प्राप्त होते हैं, लेकिन अवधारणा लिस्प के लैम्ब्डा अभिव्यक्तियों के लिए 1 9 58 में सभी तरह से होती है। अज्ञात कोड ब्लॉक के उल्लेख पर, लेकिन कम से कम अब, लैम्ब्डा अभिव्यक्तियों के उल्लेख पर, आपको यह जानना चाहिए कि इस अंतर्निहित चौथे विधि पैरामीटर का प्रतिनिधित्व कैसे करें: एक प्रतिनिधि प्रकार, अधिक विशेष रूप से, Func
।
तो, yield
क्या है? यह ब्लॉक पर नियंत्रण स्थानांतरित करता है। यह मूल रूप से एक चर को आमंत्रित करने के बिना एक ब्लॉक को आविष्कार करने का एक बहुत ही सुविधाजनक तरीका है और फिर इसे कॉल करना है।
# Create window for data refresh
real_ttl = ttl + generation_time * 2
stale_key = "#{key}.stale"
यह #{foo}
वाक्य रचना स्ट्रिंग प्रक्षेप कहा जाता है। इसका मतलब है "ब्रेसिज़ के बीच अभिव्यक्ति का मूल्यांकन करने के परिणामस्वरूप स्ट्रिंग के अंदर टोकन को प्रतिस्थापित करें"। यह String.Format()
का एक बहुत ही संक्षिप्त संस्करण है, जो वास्तव में हम इसका अनुवाद करने जा रहे हैं।
# Try to get data from memcache
value = get(key)
stale = get(stale_key)
# If stale key has expired, it is time to re-generate our data
unless stale
put(stale_key, STALE_REFRESH, generation_time) # lock
value = nil # force data re-generation
end
# If no data retrieved or data re-generation forced, re-generate data and reset stale key
unless value
value = yield
put(key, value, real_ttl)
put(stale_key, STALE_CREATED, ttl) # unlock
end
return value
end
end
यह मेरी सी # करने के लिए रूबी संस्करण का अनुवाद पर कमजोर प्रयास है:
public class Cache<Tkey, Tvalue> {
enum Stale { Refresh, Created }
/* Caches data received from a delegate
*
* The difference between this method and usual Cache.get
* is following: this method caches data and allows user
* to re-generate data when it is expired w/o running
* data generation code more than once so dog-pile effect
* won't bring our servers down
*/
public static Tvalue SmartGet(Tkey key, TimeSpan ttl, TimeSpan generationTime, Func<Tvalue> strategy)
{
// Create window for data refresh
var realTtl = ttl + generationTime * 2;
var staleKey = String.Format("{0}stale", key);
// Try to get data from memcache
var value = Get(key);
var stale = Get(staleKey);
// If stale key has expired, it is time to re-generate our data
if (stale == null)
{
Put(staleKey, Stale.Refresh, generationTime); // lock
value = null; // force data re-generation
}
// If no data retrieved or data re-generation forced, re-generate data and reset stale key
if (value == null)
{
value = strategy();
Put(key, value, realTtl);
Put(staleKey, Stale.Created, ttl) // unlock
}
return value;
}
// Fallback to default caching approach if no ttl given
public static Tvalue SmartGet(Tkey key, Func<Tvalue> strategy) =>
Get(key, strategy);
// Simulate default argument for generationTime
// C# 4.0 has default arguments, so this wouldn't be needed.
public static Tvalue SmartGet(Tkey key, TimeSpan ttl, Func<Tvalue> strategy) =>
SmartGet(key, ttl, new TimeSpan(0, 0, 30), strategy);
// Convenience overloads to allow calling it the same way as
// in Ruby, by just passing in the timespans as integers in
// seconds.
public static Tvalue SmartGet(Tkey key, int ttl, int generationTime, Func<Tvalue> strategy) =>
SmartGet(key, new TimeSpan(0, 0, ttl), new TimeSpan(0, 0, generationTime), strategy);
public static Tvalue SmartGet(Tkey key, int ttl, Func<Tvalue> strategy) =>
SmartGet(key, new TimeSpan(0, 0, ttl), strategy);
}
कृपया ध्यान दें कि मैं सी # पता नहीं है, मैं नेट पता नहीं है, मैं इस परीक्षण नहीं किया है, मैं यह भी नहीं पता कि यह वाक्य रचनात्मक रूप से वैध है या नहीं। उम्मीद है कि यह वैसे भी मदद करता है।
@ जोर्ग - अगर आप रुबी से सी # रूपांतरण के लिए कोड पोस्ट करते हैं तो क्या आप मेरी मदद करेंगे ??? – maliks
सही उत्तर: अच्छा स्पष्टीकरण + कोड – trinalbadger587