ইন্টারনেটে এই প্রশ্নের জন্য ইতিমধ্যে প্রচুর চমত্কার উত্তর রয়েছে। আমি এই বিষয়টি সম্পর্কে যে সমস্ত ব্যাখ্যা এবং উদাহরণ সংগ্রহ করেছি তার সংকলন লিখব, যদি কারও পক্ষে এটির সহায়ক হতে পারে তবে
সূচনা
কল-বাই-মান (সিবিভি)
সাধারণত, ফাংশনগুলির পরামিতিগুলি কল-বাই-মান পরামিতি হয়; অর্থাৎ প্যারামিটারগুলি ফাংশনটি নিজেই মূল্যায়নের আগে তাদের মান নির্ধারণ করতে বাম থেকে ডানদিকে মূল্যায়ন করা হয়
def first(a: Int, b: Int): Int = a
first(3 + 4, 5 + 6) // will be reduced to first(7, 5 + 6), then first(7, 11), and then 7
কল-বাই-নাম (সিবিএন)
তবে আমাদের যদি এমন কোনও ফাংশন লিখতে হবে যা পরামিতি হিসাবে এমন একটি অভিব্যক্তি হিসাবে গ্রহণ করে যা আমাদের ফাংশনটির মধ্যে না বলা পর্যন্ত মূল্যায়ন না করে? এই পরিস্থিতিতে, স্কালা কল-বাই নাম পরামিতি অফার করে। অর্থাত প্যারামিটারটি যেমন হয় তেমন কার্যক্রমে চলে যায় এবং এর মূল্যায়ন প্রতিস্থাপনের পরে ঘটে
def first1(a: Int, b: => Int): Int = a
first1(3 + 4, 5 + 6) // will be reduced to (3 + 4) and then to 7
একটি কল-টু-নাম মেকানিজম কলটিতে একটি কোড ব্লককে পাস করে এবং প্রতিবার কল প্যারামিটারে প্রবেশ করে, কোড ব্লকটি কার্যকর করা হয় এবং মান গণনা করা হয়। নিম্নলিখিত উদাহরণে, বিলম্বিত একটি বার্তা প্রিন্ট করে যা দেখায় যে পদ্ধতিটি প্রবেশ করা হয়েছে। এরপরে, বিলম্বিত একটি বার্তা এর মান সহ মুদ্রণ করে। অবশেষে, বিলম্বিত রিটার্ন 'টি':
object Demo {
def main(args: Array[String]) {
delayed(time());
}
def time() = {
println("Getting time in nano seconds")
System.nanoTime
}
def delayed( t: => Long ) = {
println("In delayed method")
println("Param: " + t)
}
}
বিলম্বিত পদ্ধতিতে
ন্যানো সেকেন্ডে সময় পাওয়া
পরম: 2027245119786400
প্রতিটি ক্ষেত্রে জন্য পেশাদার এবং কনস
সিবিএন:
+ আরও প্রায়শই টার্মিনেট করে * উপরের সমাপ্তির নীচে চেক করুন * + কোনও সুবিধা রয়েছে যে কোনও ফাংশন যুক্তির মূল্যায়ন না করা হয় যদি সংশ্লিষ্ট পরামিতি ফাংশন বডিটির মূল্যায়নে অব্যবহৃত থাকে - এটি ধীর হয়, এটি আরও ক্লাস তৈরি করে (যার অর্থ প্রোগ্রামটি নেয় আর লোড করা) এবং এটি আরও মেমরি গ্রাস করে।
সিবিভি:
+ এটি প্রায়শই সিবিএন এর চেয়ে তাত্পর্যপূর্ণভাবে আরও দক্ষ হয়, কারণ এটি পুনরাবৃত্তি যুক্তি প্রকাশের পুনরাবৃত্তিটি এড়িয়ে যায় যা নাম দ্বারা ডাকে। এটি প্রতিটি ফাংশন আর্গুমেন্টকে একবারে মূল্যায়ন করে + এটি অপরিহার্য প্রভাব এবং পার্শ্ব প্রতিক্রিয়াগুলির সাথে অনেক ভাল খেলে, কারণ আপনার অভিব্যক্তিগুলি যখন মূল্যায়ন করা হয় তখন আপনি আরও ভাল করে জানতে চান। এটির পরামিতিগুলির মূল্যায়নের সময় এটি লুপ হতে পারে * উপরের সমাপ্তির নীচে চেক *
সমাপ্তির গ্যারান্টি না থাকলে কী হবে?
-যদি কোনও অভিব্যক্তির সিবিভির মূল্যায়ন ই শেষ হয়ে যায়, তারপরে সিবিএন মূল্যায়নও ই সমাপ্ত করে দেয় - অন্য দিকটি সত্য নয়
অবসানহীন উদাহরণ
def first(x:Int, y:Int)=x
প্রথমে ভাবটি বিবেচনা করুন (1, লুপ)
সিবিএন: প্রথম (1, লুপ) → 1 সিবিভি: প্রথম (1, লুপ) expression এই অভিব্যক্তিটির যুক্তিগুলি হ্রাস করুন। যেহেতু একটি লুপ, এটি যুক্তিগুলি অনন্যভাবে হ্রাস করে। এটি শেষ হয় না
প্রতিটি ক্ষেত্রে আচরণের বিভিন্ন
আসুন যে একটি পদ্ধতি পরীক্ষা সংজ্ঞায়িত করা যাক
Def test(x:Int, y:Int) = x * x //for call-by-value
Def test(x: => Int, y: => Int) = x * x //for call-by-name
কেস 1 পরীক্ষা (2,3)
test(2,3) → 2*2 → 4
যেহেতু আমরা ইতিমধ্যে মূল্যায়িত যুক্তি দিয়ে শুরু করি এটি কল-বাই-মান এবং কল-বাই নাম অনুসারে সমান পরিমাণ পদক্ষেপ হবে
কেস 2 পরীক্ষা (3 + 4,8)
call-by-value: test(3+4,8) → test(7,8) → 7 * 7 → 49
call-by-name: (3+4)*(3+4) → 7 * (3+4) → 7 * 7 → 49
এই ক্ষেত্রে কল-বাই-মান কম পদক্ষেপগুলি সম্পাদন করে
কেস 3 পরীক্ষা (7, 2 * 4)
call-by-value: test(7, 2*4) → test(7,8) → 7 * 7 → 49
call-by-name: (7)*(7) → 49
আমরা দ্বিতীয় তর্কটির অপ্রয়োজনীয় গণনা এড়িয়ে চলি
কেস 4 পরীক্ষা (3 + 4, 2 * 4)
call-by-value: test(7, 2*4) → test(7,8) → 7 * 7 → 49
call-by-name: (3+4)*(3+4) → 7*(3+4) → 7*7 → 49
বিভিন্ন পদ্ধতির
প্রথমে, ধরে নেওয়া যাক আমাদের একটি পার্শ্ব-প্রতিক্রিয়াযুক্ত একটি ফাংশন রয়েছে। এই ফাংশনটি কিছু প্রিন্ট করে এবং তারপরে একটি int প্রদান করে।
def something() = {
println("calling something")
1 // return value
}
এখন আমরা দুটি ফাংশন সংজ্ঞায়িত করতে যাচ্ছি যে আন্ত আর্গুমেন্টগুলি গ্রহণ করে ঠিক সেইগুলি ব্যতীত একজন কল-বাই-মান শৈলীতে (x: Int) এবং অন্যটি কল-বাই-নাম শৈলীতে (x: => ইনট)
def callByValue(x: Int) = {
println("x1=" + x)
println("x2=" + x)
}
def callByName(x: => Int) = {
println("x1=" + x)
println("x2=" + x)
}
এখন যখন আমরা তাদের আমাদের পার্শ্ব-কার্যকারী ফাংশন দিয়ে ডাকি তখন কী হয়?
scala> callByValue(something())
calling something
x1=1
x2=1
scala> callByName(something())
calling something
x1=1
calling something
x2=1
সুতরাং আপনি দেখতে পাচ্ছেন যে কল-বাই-মান সংস্করণে, পাস-ইন ফাংশন কল (কিছু ()) এর পার্শ্ব-প্রতিক্রিয়াটি কেবল একবার হয়েছিল। তবে, কল-বাই-নাম সংস্করণে, পার্শ্ব-প্রতিক্রিয়াটি দু'বার হয়েছিল।
এটি কারণ কল-বাই-মান ফাংশনগুলি ফাংশনটি বলার আগে পাস-ইন এক্সপ্রেশনটির মানটি গণনা করে, সুতরাং প্রতিবার একই মানটি অ্যাক্সেস করা হয়। যাইহোক, কল-টু-নাম ফাংশনগুলি যতবার প্রবেশ করা যায় ততবার পাস-ইন এক্সপ্রেশনটির মানটিকে পুনরায় সঞ্চার করে।
নামটি দিয়ে কল করুন - এটি ব্যবহারের চেয়ে ভাল যেখানে উদাহরণ
থেকে: https://stackoverflow.com/a/19036068/1773841
সাধারণ সম্পাদনের উদাহরণ: লগিং।
এর মত একটি ইন্টারফেস কল্পনা করা যাক:
trait Logger {
def info(msg: => String)
def warn(msg: => String)
def error(msg: => String)
}
এবং তারপরে এটি ব্যবহার করা হয়েছে:
logger.info("Time spent on X: " + computeTimeSpent)
যদি তথ্য পদ্ধতিটি কিছু না করে (কারণ, বলুন যে লগিং স্তরটি তার চেয়ে বেশিের জন্য কনফিগার করা হয়েছিল), তবে কমপিউটিটাইমস্পেন্টকে কখনই সময় বলা হয় না, সময় সাশ্রয় করতে হবে। লগারের সাথে এটি অনেক ঘটে, যেখানে কেউ প্রায়শই স্ট্রিং ম্যানিপুলেশন দেখেন যা লগ হওয়া কাজের তুলনায় ব্যয়বহুল হতে পারে।
সঠিকতার উদাহরণ: লজিক অপারেটরগুলি।
আপনি সম্ভবত কোডটি দেখেছেন:
if (ref != null && ref.isSomething)
কল্পনা করুন যে আপনি && পদ্ধতিটি এর মতো ঘোষণা করবেন:
trait Boolean {
def &&(other: Boolean): Boolean
}
তারপরে, যখনই রেফ শালীন হয়, আপনি একটি ত্রুটি পাবেন কারণ && এ যাওয়ার আগে কিছুকে নালারফেরেন্সের জন্য ডাকা হবে। এই কারণে, আসল ঘোষণাটি হ'ল:
trait Boolean {
def &&(other: => Boolean): Boolean =
if (this) this else other
}
=> Int
এর থেকে আলাদা ধরনেরInt
; এটিInt
"বনাম জাস্ট" কোনও আর্গুমেন্টের ক্রিয়াকলাপInt
। একবার আপনি প্রথম শ্রেণীর ফাংশন পেয়েছেন আপনি না প্রয়োজন উদ্ভাবিত থেকে কল-বাই-নাম পরিভাষা এই বর্ণনা করতে।