दोनों के बीच क्या अंतर है:
def even: Int => Boolean = _ % 2 == 0
तथा
val even: Int => Boolean = _ % 2 == 0
दोनों को बुलाया जा सकता है even(10)
।
दोनों के बीच क्या अंतर है:
def even: Int => Boolean = _ % 2 == 0
तथा
val even: Int => Boolean = _ % 2 == 0
दोनों को बुलाया जा सकता है even(10)
।
जवाबों:
विधि def even
कॉल पर मूल्यांकन करती है और हर बार (नया उदाहरण Function1
) नया फ़ंक्शन बनाती है ।
def even: Int => Boolean = _ % 2 == 0
even eq even
//Boolean = false
val even: Int => Boolean = _ % 2 == 0
even eq even
//Boolean = true
साथ def
आप हर कॉल पर नया कार्य प्राप्त कर सकते हैं:
val test: () => Int = {
val r = util.Random.nextInt
() => r
}
test()
// Int = -1049057402
test()
// Int = -1049057402 - same result
def test: () => Int = {
val r = util.Random.nextInt
() => r
}
test()
// Int = -240885810
test()
// Int = -1002157461 - new result
val
परिभाषित होने पर मूल्यांकन करता है, def
- जब बुलाया जाता है:
scala> val even: Int => Boolean = ???
scala.NotImplementedError: an implementation is missing
scala> def even: Int => Boolean = ???
even: Int => Boolean
scala> even
scala.NotImplementedError: an implementation is missing
ध्यान दें कि एक तीसरा विकल्प है lazy val
:।
पहली बार कॉल करने पर यह मूल्यांकन करता है:
scala> lazy val even: Int => Boolean = ???
even: Int => Boolean = <lazy>
scala> even
scala.NotImplementedError: an implementation is missing
लेकिन FunctionN
हर बार एक ही परिणाम (इस मामले में एक ही उदाहरण ) देता है:
lazy val even: Int => Boolean = _ % 2 == 0
even eq even
//Boolean = true
lazy val test: () => Int = {
val r = util.Random.nextInt
() => r
}
test()
// Int = -1068569869
test()
// Int = -1068569869 - same result
प्रदर्शन
val
परिभाषित होने पर मूल्यांकन करता है।
def
हर कॉल पर मूल्यांकन करता है, इसलिए प्रदर्शन val
कई कॉल के लिए खराब हो सकता है । आपको एकल कॉल के साथ समान प्रदर्शन मिलेगा। और बिना किसी कॉल के आपको कोई ओवरहेड नहीं मिलेगा def
, इसलिए आप इसे परिभाषित कर सकते हैं, भले ही आप इसे कुछ शाखाओं में उपयोग न करें।
एक साथ lazy val
आप एक आलसी मूल्यांकन मिल जाएगा: आप इसे परिभाषित कर सकते हैं, भले ही आप कुछ शाखाओं में इसका इस्तेमाल नहीं होगा, और यह एक बार या कभी नहीं का मूल्यांकन करता है, लेकिन आप अपने लिए हर उपयोग पर दोहरी जांच लॉकिंग से थोड़ी भूमि के ऊपर मिल जाएगा lazy val
।
जैसा कि @SargeBorsch ने नोट किया कि आप विधि को परिभाषित कर सकते हैं, और यह सबसे तेज़ विकल्प है:
def even(i: Int): Boolean = i % 2 == 0
लेकिन अगर आपको फंक्शन कंपोजिशन के लिए फंक्शन (मेथड मेथड) की जरूरत है या हाई ऑर्डर फंक्शंस (जैसे filter(even)
) कंपाइलर आपके फंक्शन से हर बार फंक्शन के रूप में यूज कर रहे हैं, तो परफॉर्मेंस थोड़ी खराब हो सकती है val
।
even
है।
def
एक विधि को परिभाषित करने के लिए इस्तेमाल किया जा सकता है, और यह सबसे तेज़ विकल्प है। @ ए। करीमी
even eq even
।
@inline
विशेषता है। लेकिन यह इनलाइन फ़ंक्शन नहीं कर सकता क्योंकि फ़ंक्शन कॉल apply
एक फ़ंक्शन ऑब्जेक्ट के वर्चुअल विधि के लिए कॉल है । JVM कुछ स्थितियों में ऐसे कॉलों को समर्पित और इनलाइन कर सकता है, लेकिन सामान्य रूप से नहीं।
इस पर विचार करो:
scala> def even: (Int => Boolean) = {
println("def");
(x => x % 2 == 0)
}
even: Int => Boolean
scala> val even2: (Int => Boolean) = {
println("val");
(x => x % 2 == 0)
}
val //gets printed while declaration. line-4
even2: Int => Boolean = <function1>
scala> even(1)
def
res9: Boolean = false
scala> even2(1)
res10: Boolean = false
आपको फर्क दिखता हैं? संक्षेप में:
def : हर कॉल के लिए even
, यह even
विधि के शरीर को फिर से कॉल करता है । लेकिन साथ even2
यानी वैल , समारोह केवल एक बार, जबकि घोषणा (और इसलिए यह प्रिंट आरंभ नहीं हो जाता val
लाइन 4 पर और फिर कभी नहीं) और एक ही आउटपुट प्रत्येक बार इस तक पहुंच जाता है। उदाहरण के लिए ऐसा करने का प्रयास करें:
scala> import scala.util.Random
import scala.util.Random
scala> val x = { Random.nextInt }
x: Int = -1307706866
scala> x
res0: Int = -1307706866
scala> x
res1: Int = -1307706866
जब x
प्रारंभ किया जाता है, Random.nextInt
तो अंतिम मान के रूप में सेट किया गया मान लौटाया जाता है x
। अगली बार x
फिर से उपयोग किया जाता है, यह हमेशा समान मूल्य लौटाएगा।
आप आलसी को इनिशियलाइज़ भी कर सकते हैं x
। अर्थात पहली बार इसका उपयोग किया जाता है, यह आरंभिक होता है और घोषणा के समय नहीं। उदाहरण के लिए:
scala> lazy val y = { Random.nextInt }
y: Int = <lazy>
scala> y
res4: Int = 323930673
scala> y
res5: Int = 323930673
even2
दो बार कॉल करने की कोशिश करें , एक बार 1
और एक बार साथ 2
। आपको प्रत्येक कॉल में अलग-अलग उत्तर मिलेंगे। इसलिए, जबकि println
बाद के कॉल में निष्पादित नहीं किया जाता है , तो आपको अलग-अलग कॉल से समान परिणाम नहीं मिलता है even2
। जैसा कि println
फिर से निष्पादित क्यों नहीं किया गया है, यह एक अलग सवाल है।
यह देखो:
var x = 2 // using var as I need to change it to 3 later
val sq = x*x // evaluates right now
x = 3 // no effect! sq is already evaluated
println(sq)
हैरानी की बात है, यह 4 नहीं 9 मुद्रित करेगा! वैल (यहां तक कि var) का मूल्यांकन तुरंत और सौंपा गया है।
अब बदलो वैल टू डिफ .. ये छपेगा 9! Def एक फंक्शन कॉल है .. यह हर बार मूल्यांकन करेगा जिसे यह कहा जाता है।
वैल यानी "वर्ग" स्कैला की परिभाषा के अनुसार है। यह घोषणा के समय सही मूल्यांकन किया जाता है, आप बाद में बदल नहीं सकते। अन्य उदाहरणों में, जहां सम 2 भी वैल है, लेकिन यह फंक्शन सिग्नेचर अर्थात "(इंट => बुलियन)" के साथ घोषित किया गया है, इसलिए यह इंट टाइप नहीं है। यह एक फंक्शन है और यह एक्सप्रेशन को फॉलो करके सेट होता है
{
println("val");
(x => x % 2 == 0)
}
स्काला वैली प्रॉपर्टी के अनुसार, आप एक और फंक्शन को सम 2 तक असाइन नहीं कर सकते हैं, एक ही नियम जैसे कि वर्ग।
Eval2 वैल फ़ंक्शन को कॉल करने के बारे में बार-बार "वैल" क्यों नहीं प्रिंट हो रहा है?
मूल कोड:
val even2: (Int => Boolean) = {
println("val");
(x => x % 2 == 0)
}
हम जानते हैं, स्लाला के अंतिम कथन में उपरोक्त प्रकार की अभिव्यक्ति ({..} के अंदर) वास्तव में बाएं हाथ की ओर है। तो आप अंत में समरूप 2 को "x => x% 2 == 0" फ़ंक्शन पर सेट करते हैं, जो आपके द्वारा समान रूप से 2 वेल प्रकार (यानी => बूलियन) के लिए घोषित प्रकार से मेल खाता है, इसलिए कंपाइलर खुश है। अब भी 2 केवल "(x => x% 2 == 0)" फ़ंक्शन को इंगित करता है (अर्थात प्रिंटनल ("वैल") से पहले कोई अन्य बयान नहीं) विभिन्न मापदंडों के साथ इवेंट 2 को लागू करना वास्तव में लागू होगा "(x => x% 2 == 0) "कोड, जो केवल event2 के साथ सहेजा जाता है।
scala> even2(2)
res7: Boolean = true
scala> even2(3)
res8: Boolean = false
बस इसे और अधिक स्पष्ट करने के लिए, निम्नलिखित कोड के विभिन्न संस्करण हैं।
scala> val even2: (Int => Boolean) = {
| println("val");
| (x => {
| println("inside final fn")
| x % 2 == 0
| })
| }
क्या होगा ? यहां हम बार-बार प्रिंट किए गए "इनसाइड फ़ाइनल fn" को देखते हैं, जब आप इवन 2 () कहते हैं।
scala> even2(3)
inside final fn
res9: Boolean = false
scala> even2(2)
inside final fn
res10: Boolean = true
scala>
परिभाषा को निष्पादित करना जैसे def x = e
कि अभिव्यक्ति का मूल्यांकन नहीं करेगा ई। जब भी x का आह्वान किया जाता है, तब स्थिर ई का मूल्यांकन किया जाता है।
वैकल्पिक रूप से, स्काला एक मूल्य परिभाषा प्रदान करता है val x = e
, जो परिभाषा के
मूल्यांकन के भाग के रूप में दाईं ओर का मूल्यांकन करता है। यदि बाद में एक्स का उपयोग किया जाता है, तो इसे तुरंत ई के पूर्व-गणना मूल्य द्वारा बदल दिया जाता है, ताकि अभिव्यक्ति का फिर से मूल्यांकन करने की आवश्यकता न हो।
इसके अलावा, वैल एक वैल्यू मूल्यांकन है। जिसका अर्थ है कि दाएं हाथ की अभिव्यक्ति का मूल्यांकन परिभाषा के दौरान किया जाता है। जहां Def का नाम मूल्यांकन से होता है। इसका उपयोग करने तक इसका मूल्यांकन नहीं होगा।
उपरोक्त सहायक उत्तरों के अलावा, मेरे निष्कर्ष हैं:
def test1: Int => Int = {
x => x
}
--test1: test1[] => Int => Int
def test2(): Int => Int = {
x => x+1
}
--test2: test2[]() => Int => Int
def test3(): Int = 4
--test3: test3[]() => Int
ऊपर दिखाया गया है कि "डीफ़" एक विधि है (शून्य तर्क मापदंडों के साथ) जो एक और फ़ंक्शन "Int => Int" देता है जब आह्वान किया जाता है।
कार्यों के तरीकों का रूपांतरण यहाँ अच्छी तरह से समझाया गया है: https://tpolecat.github.io/2014/06/09/methods-functions.html
REPL में,
scala> def even: Int => Boolean = { _% 2 == 0 }
even: Int => Boolean
scala> val even: Int => Boolean = { _% 2 == 0 }
even: Int => Boolean = $$Lambda$1157/1017502292@57a0aeb8
def का मतलब है call-by-name
, मांग पर मूल्यांकन
वैल का मतलब है call-by-value
, प्रारंभिक मूल्यांकन करते समय मूल्यांकन किया गया
Int => Boolean
मतलब है? मुझे लगता है कि परिभाषित वाक्य रचना हैdef foo(bar: Baz): Bin = expr