অলস ভাল কি করে?


247

আমি লক্ষ্য করেছি যে স্কেলা সরবরাহ করে lazy vals। তবে তারা যা করে আমি তা পাই না।

scala> val x = 15
x: Int = 15

scala> lazy val y = 13
y: Int = <lazy>

scala> x
res0: Int = 15

scala> y
res1: Int = 13

REPL অনুষ্ঠান yএকটি হল lazy val, কিন্তু এটা কিভাবে একটি স্বাভাবিক থেকে ভিন্ন val?

উত্তর:


335

তাদের মধ্যে পার্থক্যটি হ'ল valএটি যখন নির্ধারিত lazy valহয় তখন এটি কার্যকর করা হয় এবং যখন প্রথমবার অ্যাক্সেস করা হয় তখন একটি কার্যকর করা হয়।

scala> val x = { println("x"); 15 }
x
x: Int = 15

scala> lazy val y = { println("y"); 13 }
y: Int = <lazy>

scala> x
res2: Int = 15

scala> y
y
res3: Int = 13

scala> y
res4: Int = 13

একটি পদ্ধতির বিপরীতে (সংজ্ঞায়িত def) এ lazy valএকবার কার্যকর করা হয় এবং তারপরে আর কখনও হয় না। এটি কার্যকর হতে পারে যখন কোনও অপারেশন সম্পূর্ণ হতে দীর্ঘ সময় নেয় এবং যখন এটি পরে ব্যবহৃত হয় তা নিশ্চিত না হয়।

scala> class X { val x = { Thread.sleep(2000); 15 } }
defined class X

scala> class Y { lazy val y = { Thread.sleep(2000); 13 } }
defined class Y

scala> new X
res5: X = X@262505b7 // we have to wait two seconds to the result

scala> new Y
res6: Y = Y@1555bd22 // this appears immediately

এখানে, যখন মানগুলি xএবং yকখনই ব্যবহৃত হয় না, কেবল xঅকারণে সম্পদ নষ্ট করে। যদি আমরা মনে করি yএর কোনও পার্শ্ব প্রতিক্রিয়া নেই এবং এটি যে কতবার অ্যাক্সেস করা হয় তা আমরা জানি না (কখনই, একবারও হাজার বার নয়) এটি হিসাবে ঘোষণা করা অযথাdef যেহেতু আমরা বেশ কয়েকবার এটি কার্যকর করতে চাই না তা ।

আপনি কীভাবে lazy valsবাস্তবায়ন হয় তা জানতে চাইলে এই প্রশ্নটি দেখুন


65
পরিপূরক হিসাবে: @ ভিক্টরক্ল্যাং টুইটারে পোস্ট করেছেন: "
পিটার স্মিটজ

@ পিটারস্কিমেটস এবং আমি এটি ভয়াবহ মনে করি। Lazy<T>নেট মধ্যে তুলনা করুন
পাভেল ভোরোনিন

61

এই বৈশিষ্ট্যটি কেবল ব্যয়বহুল গণনাগুলিতে বিলম্ব করতে সহায়তা করে না, তবে পারস্পরিক নির্ভরশীল বা চক্রীয় কাঠামোগত গঠনেও কার্যকর। যেমন এটি স্ট্যাকের ওভারফ্লোতে বাড়ে:

trait Foo { val foo: Foo }
case class Fee extends Foo { val foo = Faa() }
case class Faa extends Foo { val foo = Fee() }

println(Fee().foo)
//StackOverflowException

তবে অলস ভ্যালস দিয়ে এটি ভাল কাজ করে

trait Foo { val foo: Foo }
case class Fee extends Foo { lazy val foo = Faa() }
case class Faa extends Foo { lazy val foo = Fee() }

println(Fee().foo)
//Faa()

যদি আপনার টস্ট্রিং পদ্ধতিটি "ফু" বৈশিষ্ট্যটি আউটপুট দেয় তবে এটি একই স্ট্যাকওভারফ্লো এক্সপিসনেসনে পৌঁছে যাবে। যাইহোক "অলস" এর দুর্দান্ত উদাহরণ !!!
ফুয়াদ এফেন্দি

39

আমি বুঝতে পারি যে উত্তরটি দেওয়া হয়েছে তবে আমি আমার মতো নতুনদের পক্ষে এটি সহজ করে বোঝার জন্য একটি সহজ উদাহরণ লিখেছিলাম:

var x = { println("x"); 15 }
lazy val y = { println("y"); x+1 }
println("-----")
x = 17
println("y is: " + y)

উপরের কোডের আউটপুট হল:

x
-----
y
y is: 18

যেমনটি দেখা যায়, এটি প্রারম্ভিক হওয়ার সময় এক্স মুদ্রিত হয়, তবে একইভাবে আরম্ভ করা হলে y প্রিন্ট করা হয় না (আমি x ইচ্ছাকৃতভাবে বর্ণ হিসাবে এখানে নিয়েছি - y কখন আরম্ভ হয় তা ব্যাখ্যা করার জন্য)। এরপরে যখন y বলা হবে, এটি আরম্ভের পাশাপাশি শেষ 'x' এর মান বিবেচনা করা হবে তবে পুরানোটি নয়।

আশাকরি এটা সাহায্য করবে.


35

একটি অলস ভ্যালটি " মেমোইজড (নো- আরগ ) ডিএফ " হিসাবে সহজেই বোঝা যায় ।

একটি ডিএফের মতো, অলস ভালটি চালিত না হওয়া পর্যন্ত মূল্যায়ন করা হয় না। তবে ফলাফলটি সংরক্ষণ করা হয় যাতে পরবর্তী অনুরোধগুলি সংরক্ষিত মানটি ফেরত দেয়। স্মৃতিযুক্ত ফলাফলটি আপনার ডেটা কাঠামোতে একটি ভালকের মতো স্থান গ্রহণ করে।

অন্যরা যেমন বলেছে, অলস ভ্যালের ব্যবহারের ক্ষেত্রে ব্যয়বহুল গণনাগুলি প্রয়োজন হয় না হওয়া পর্যন্ত তাদের ফলাফলগুলি সংরক্ষণ করা এবং মানগুলির মধ্যে নির্দিষ্ট বিজ্ঞপ্তি নির্ভরতা সমাধান করা expensive

অলস ভ্যালস প্রকৃতপক্ষে কমবেশি স্মৃতিবদ্ধ ডিফল্ট হিসাবে প্রয়োগ করা হয়। আপনি তাদের প্রয়োগের বিশদ সম্পর্কে এখানে পড়তে পারেন:

http://docs.scala-lang.org/sips/pending/improved-lazy-val-initialization.html


1
সম্ভবত এটি একটি "স্মৃতিযুক্ত ডিফ হিসাবে 0 টি আর্গুমেন্ট নেয়"।
আন্দ্রে টিউকিন

19

এছাড়াও lazyনিম্নলিখিত কোড হিসাবে, আবর্তনশীল নির্ভরতা ছাড়া দরকারী হল:

abstract class X {
  val x: String
  println ("x is "+x.length)
}

object Y extends X { val x = "Hello" }
Y

অ্যাক্সেস Yএখন নাল পয়েন্টার ব্যতিক্রম নিক্ষেপ করবে, কারণ xএটি এখনও আরম্ভ করা হয়নি। নিম্নলিখিতটি ঠিকঠাকভাবে কাজ করে:

abstract class X {
  val x: String
  println ("x is "+x.length)
}

object Y extends X { lazy val x = "Hello" }
Y

সম্পাদনা: নিম্নলিখিতগুলিও কাজ করবে:

object Y extends { val x = "Hello" } with X 

একে বলা হয় "প্রাথমিক শুরুর দিকে"। দেখুন এই তাই প্রশ্ন আরো বিস্তারিত জানার জন্য।


11
আপনি কি স্পষ্ট করে বলতে পারবেন যে ওয়াইয়ের ঘোষণাটি প্যারেন্ট কন্সট্রাক্টরকে কল করার আগে প্রথম উদাহরণে তাত্ক্ষণিক "x" পরিবর্তন করে না কেন?
আশোয়াত

2
কারণ সুপারক্লাস কনস্ট্রাক্টর হ'ল প্রথমটি যা স্পষ্টভাবে কল হয়।
স্টিভো স্লাভিć

@ আশোয়াত দয়া করে কেন এটি আরম্ভ করা হচ্ছে না তার ব্যাখ্যার জন্য এই লিঙ্কটি দেখুন ।
Jus12

4

lazyউপরের সংজ্ঞায়িত হিসাবে - এর একটি প্রদর্শন - অ্যাক্সেসের সময় বনাম কার্যকরকরণ নির্ধারিত হলে কার্যকর করা: (2.12.7 স্কেল শেল ব্যবহার করে)

// compiler says this is ok when it is lazy
scala> lazy val t: Int = t 
t: Int = <lazy>
//however when executed, t recursively calls itself, and causes a StackOverflowError
scala> t             
java.lang.StackOverflowError
...

// when the t is initialized to itself un-lazily, the compiler warns you of the recursive call
scala> val t: Int = t
<console>:12: warning: value t does nothing other than call itself recursively
   val t: Int = t

1
scala> lazy val lazyEight = {
     |   println("I am lazy !")
     |   8
     | }
lazyEight: Int = <lazy>

scala> lazyEight
I am lazy !
res1: Int = 8
  • সমস্ত vals অবজেক্ট নির্মাণের সময় আরম্ভ করা হয়
  • প্রথম ব্যবহার না হওয়া পর্যন্ত সূচনা স্থগিত করতে অলস কীওয়ার্ডটি ব্যবহার করুন
  • মনোযোগ দিন : অলস ভ্যালসগুলি চূড়ান্ত নয় এবং তাই পারফরম্যান্সের ঘাটতিগুলি দেখাতে পারে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.