=>, () => এবং ইউনিট => এর মধ্যে পার্থক্য কী


153

আমি এমন একটি ফাংশন উপস্থাপন করার চেষ্টা করছি যা কোনও আর্গুমেন্ট না নিয়ে এবং কোনও মান দেয় না (আমি জাভাস্ক্রিপ্টে সেটটাইমআউট ফাংশনটি সিমুলেট করছি, যদি আপনার অবশ্যই জানা থাকে))

case class Scheduled(time : Int, callback :  => Unit)

"` ভাল 'পরামিতি কল-বাই নাম নাও হতে পারে "বলে সংকলন করে না

case class Scheduled(time : Int, callback :  () => Unit)  

সংকলন করে তবে তার পরিবর্তে অদ্ভুতভাবে আহ্বান জানাতে হবে

Scheduled(40, { println("x") } )

আমাকে এটা করতেই হবে

Scheduled(40, { () => println("x") } )      

যা কাজ করে তাও

class Scheduled(time : Int, callback :  Unit => Unit)

তবে এটি একটি আরও কম-সংবেদনশীল উপায়ে ডাকা হয়

 Scheduled(40, { x : Unit => println("x") } )

(ইউনিট ধরণের ইউনিটটির পরিবর্তনশীলতা কী হবে?) আমি অবশ্যই যা চাই তা এমন একজন নির্মাতা যা এটি একটি সাধারণ ফাংশন হলে আমি যেভাবে অনুরোধ করব সেভাবেই অনুরোধ করা যেতে পারে:

 Scheduled(40, println("x") )

বাচ্চাকে তার বোতল দিন!


3
বাই-নাম পারম সহ কেস ক্লাসগুলি ব্যবহার করার আরেকটি উপায় হ'ল তাদের একটি মাধ্যমিক প্যারামিটার তালিকায় রাখুন, যেমন case class Scheduled(time: Int)(callback: => Unit)। এটি কাজ করে কারণ গৌণ প্যারামিটারের তালিকাটি প্রকাশ্যে প্রকাশিত হয় নি, বা এটি উত্পন্ন equals/ hashCodeপদ্ধতিতে অন্তর্ভুক্ত নয় ।
নীলস্কেপ

নাম-প্যারামিটার এবং 0-আরটি ফাংশনগুলির মধ্যে পার্থক্য সম্পর্কিত আরও কয়েকটি আকর্ষণীয় দিক এই প্রশ্ন এবং উত্তরটিতে পাওয়া যায় । আমি যখন এই প্রশ্নটি পেয়েছিলাম তখন এটি আমি যা খুঁজছিলাম তা আসলে।
lex82

উত্তর:


234

নাম দ্বারা কল করুন: => টাইপ করুন

=> Typeস্বরলিপি কল-বাই-নাম, যা এক ঘোরা নানাভাবে পরামিতি প্রেরণ করা সম্ভব। আপনি যদি তাদের সাথে পরিচিত না হন তবে আমি উইকিপিডিয়া নিবন্ধটি পড়ার জন্য কিছুটা সময় নেওয়ার পরামর্শ দিই, যদিও আজকাল এটি বেশিরভাগ কল-বাই-ভ্যালু এবং কল-বাই-রেফারেন্স।

এর অর্থ হ'ল যা উত্তীর্ণ হবে তা ফাংশনের অভ্যন্তরে মান নামের জন্য প্রতিস্থাপিত হয়। উদাহরণস্বরূপ, এই ফাংশনটি গ্রহণ করুন:

def f(x: => Int) = x * x

আমি যদি এটিকে ডাকি

var y = 0
f { y += 1; y }

তারপরে কোডটি এভাবে কার্যকর করা হবে

{ y += 1; y } * { y += 1; y }

যদিও এটি শনাক্তকারী নামের সংঘর্ষের ঘটলে কী ঘটবে তা তুলে ধরে। চিরাচরিত কল-বাই-নামে, নাম সংঘর্ষ এড়ানোর জন্য ক্যাপচার-এড়ানো এস্টিটিউশন নামক একটি প্রক্রিয়া ঘটে। স্কালায়, তবে, একই ফলাফলের সাথে এটি অন্যভাবে প্রয়োগ করা হয়েছে - প্যারামিটারের ভিতরে সনাক্তকারী নামগুলি কল করা ফাংশনটিতে শ্যাডো আইডেন্টিফায়ারকে উল্লেখ করতে পারে না বা ছায়া সনাক্তকারী হতে পারে।

কল-বাই-নাম সম্পর্কিত আরও কিছু পয়েন্ট রয়েছে যা আমি অন্য দুটি ব্যাখ্যা করার পরে বলব।

0-arity ফাংশন: () => প্রকার

সিনট্যাক্সটি () => Typeএ এর ধরণের জন্য বোঝায় Function0। এটি এমন কোনও ফাংশন যা কোনও পরামিতি নেয় না এবং কোনও কিছু ফেরত দেয়। এটি পদ্ধতিটিকে কল করে বলার সমতুল্য size()- এটি কোনও পরামিতি নেয় না এবং কোনও নম্বর দেয়।

তবে এটি আকর্ষণীয় যে এই বর্ননাটি একটি বেনাম ফাংশন আক্ষরিক জন্য সিনট্যাক্সের সাথে খুব মিল , যা কিছু বিভ্রান্তির কারণ। উদাহরণ স্বরূপ,

() => println("I'm an anonymous function")

arity 0 একটি বেনামী ফাংশন আক্ষরিক, যার হয় টাইপ হয়

() => Unit

সুতরাং আমরা লিখতে পারে:

val f: () => Unit = () => println("I'm an anonymous function")

তবে মানটির সাথে ধরণের বিভ্রান্ত না করা গুরুত্বপূর্ণ।

ইউনিট => টাইপ করুন

এটি আসলে মাত্র একটি Function1, যার প্রথম প্যারামিটারটি টাইপ Unit। এটি লেখার অন্যান্য উপায় হতে পারে (Unit) => Typeবা Function1[Unit, Type]। বিষয়টি হ'ল ... এটি যা চায় তা কখনই সম্ভব না। এই Unitধরণের মূল উদ্দেশ্যটি এমন একটি মানকে নির্দেশ করছে যা একটির মধ্যে আগ্রহী নয়, সুতরাং সেই মানটি গ্রহণ করার কোনও অর্থ নেই ।

উদাহরণস্বরূপ, বিবেচনা করুন

def f(x: Unit) = ...

একজন সম্ভবত কী করতে পারে x? এর কেবলমাত্র একক মান থাকতে পারে, সুতরাং এটির গ্রহণের প্রয়োজন নেই। একটি সম্ভাব্য ব্যবহার হ'ল চেইন ফাংশনগুলি ফিরবে Unit:

val f = (x: Unit) => println("I'm f")
val g = (x: Unit) => println("I'm g")
val h = f andThen g

কারণ andThenকেবলমাত্র এতে সংজ্ঞায়িত করা হয় Function1এবং আমরা যে ক্রিয়াকলাপগুলি শৃঙ্খলাবদ্ধ করছি সেগুলি আবার ফিরে আসছে Unit, তাদের Function1[Unit, Unit]শৃঙ্খলাবদ্ধ করতে সক্ষম হওয়ার জন্য আমাদের তাদের সংজ্ঞা দিতে হয়েছিল।

বিভ্রান্তির উত্স

বিভ্রান্তির প্রথম উত্সটি টাইপ এবং আক্ষরিকের মধ্যে সাদৃশ্যটি ভাবছে যা 0-arity ফাংশনগুলির জন্য উপস্থিত রয়েছে নাম অনুসারে কল করার জন্যও বিদ্যমান। অন্য কথায়, যে চিন্তা, কারণ

() => { println("Hi!") }

() => Unitতাহলে আক্ষরিক হয়

{ println("Hi!") }

আক্ষরিক হবে => Unit। এইটা না. এটি কোডের একটি ব্লক, আক্ষরিক নয়।

বিভ্রান্তির আরেকটি উত্স হ'ল এই Unitধরণের মান লেখা হয় ()যা 0-arity প্যারামিটার তালিকার মতো দেখাচ্ছে (তবে এটি নয়)।


আমার দু'বছরের পরে প্রথমবারের মতো ডাউন-ভোট হতে পারে। কেউ ক্রিসমাসে কেস => সিনট্যাক্স সম্পর্কে ভাবছেন, এবং আমি এই উত্তরটি ক্যানোনিকাল এবং সম্পূর্ণ হিসাবে সুপারিশ করতে পারি না! বিশ্ব কোন দিকে অগ্রসর হচ্ছে? সম্ভবত মায়ানরা এক সপ্তাহের মধ্যেই বন্ধ ছিল। তারা কি সঠিকভাবে লিপ বছরগুলিতে চিত্রিত করেছিল? দিবালোক সঞ্চয়?
som-snytt

@ som-snytt আচ্ছা, প্রশ্নটি সম্পর্কে জিজ্ঞাসা করা হয়নি case ... =>, তাই আমি এটি উল্লেখ করি নি। দুঃখের হলেও সত্য. :-)
ড্যানিয়েল সি সোব্রাল

1
@ ড্যানিয়েল সি সোব্রাল আপনি দয়া করে ব্যাখ্যা করতে পারেন "এটি কোডের একটি ব্লক, আক্ষরিক নয়।" অংশ। তাহলে দুজনের মধ্যে ঠিক কী আলাদা?
নিশ 1013

2
@ নিশ 1013 একটি "আক্ষরিক" একটি মান (পূর্ণসংখ্যা 1, চরিত্র 'a', স্ট্রিং "abc", বা () => println("here")কিছু উদাহরণের জন্য ফাংশন )। এটি আর্গুমেন্ট হিসাবে রূপান্তরিত হতে পারে, ভেরিয়েবলগুলিতে সঞ্চিত ইত্যাদি code একটি "ব্লক অফ কোড" হ'ল বিবৃতিগুলির একটি সিনট্যাক্টিকাল সীমানা - এটি কোনও মান নয়, এটি কাছাকাছি যেতে পারে না বা এর মতো কিছু।
ড্যানিয়েল সি সোব্রাল

1
যে একই পার্থক্য @Alex (Unit) => Typeবনাম () => Typeপ্রথমে একটি হয় - Function1[Unit, Type]দ্বিতীয় একটি হল, Function0[Type]
ড্যানিয়েল সি।

36
case class Scheduled(time : Int, callback :  => Unit)

caseপরিবর্তক অন্তর্নিহিত তোলে valকন্সট্রাকটর প্রতিটি যুক্তি শেষ হয়ে এসেছে। অতএব (যেমন কেউ উল্লেখ করেছেন) আপনি সরিয়ে ফেললে caseআপনি কল-বাই-নাম প্যারামিটার ব্যবহার করতে পারেন। সংকলক সম্ভবত এটি যাইহোক অনুমতি দিতে পারে, কিন্তু এটি val callbackমরফিংয়ের পরিবর্তে এটি তৈরি করা হলে লোকজন আশ্চর্য হতে পারে lazy val callback

আপনি callback: () => Unitএখন বদলে যখন আপনার কেস কল-বাই নাম প্যারামিটার পরিবর্তে একটি ফাংশন নেয়। স্পষ্টতই ফাংশনটি সংরক্ষণ করা যেতে পারে val callbackতাই কোনও সমস্যা নেই।

আপনি যা চান তা পাওয়ার সহজতম উপায় ( Scheduled(40, println("x") )যেখানে একটি লাম্বদা পাস করার জন্য একটি কল-বাই নাম প্যারামিটার ব্যবহার করা হয়) সম্ভবত এড়িয়ে যাওয়া caseএবং স্পষ্টভাবে applyযেটি আপনি প্রথম স্থানে পেতে পারেননি তা তৈরি করা :

class Scheduled(val time: Int, val callback: () => Unit) {
    def doit = callback()
}

object Scheduled {
    def apply(time: Int, callback: => Unit) =
        new Scheduled(time, { () => callback })
}

ব্যাবহৃত হচ্ছে:

scala> Scheduled(1234, println("x"))
res0: Scheduled = Scheduled@5eb10190

scala> Scheduled(1234, println("x")).doit
x

3
কেন এটি কেস-শ্রেণি রাখবেন না এবং কেবলমাত্র ডিফল্ট প্রয়োগকে ওভাররাইড করবেন? এছাড়াও, সংকলকটি একটি অলস ভালে একটি উপ-নাম অনুবাদ করতে পারে না, যেহেতু তাদের অন্তর্নিহিত পৃথক শব্দার্থক শব্দ রয়েছে, অলস একবারে-একবারে এবং
ভিক্টর ক্লাং

@ ভিক্টরক্ল্যাং কীভাবে আপনি কেস ক্লাসের ডিফল্ট প্রয়োগের পদ্ধতিটিকে ওভাররাইড করতে পারেন? stackoverflow.com/questions/2660975/…
সাওয়ার

অবজেক্ট ClassName {Def প্রয়োগ (…):… =…}
ভিক্টর ক্লাং

চার বছর পরে এবং আমি বুঝতে পারি যে আমি যে উত্তরটি বেছে নিয়েছি তা কেবল শিরোনামে প্রশ্নের উত্তর দিয়েছে, আমার কাছে আসলে ছিল না (যা এটি উত্তর দেয়)।
মালভোলিও

1

প্রশ্নে, আপনি জাভাস্ক্রিপ্টে সেটটাইমআউট ফাংশন অনুকরণ করতে চান। পূর্ববর্তী উত্তরের ভিত্তিতে, আমি নিম্নলিখিত কোডটি লিখি:

class Scheduled(time: Int, cb: => Unit) {
  private def runCb = cb
}

object Scheduled {
  def apply(time: Int, cb: => Unit) = {
    val instance = new Scheduled(time, cb)
    Thread.sleep(time*1000)
    instance.runCb
  }
}

REPL- তে আমরা এর মতো কিছু পেতে পারি:

scala> Scheduled(10, println("a")); Scheduled(1, println("b"))
a
b

আমাদের সিমুলেশন সেটটাইমআউটের মতো হুবহু আচরণ করে না, কারণ আমাদের সিমুলেশনটি ব্লক করা ফাংশন, তবে সেটটাইমআউট অ-ব্লক করা।


0

আমি এটি এইভাবে করি (কেবল প্রয়োগ ভাঙতে চাই না):

case class Thing[A](..., lazy: () => A) {}
object Thing {
  def of[A](..., a: => A): Thing[A] = Thing(..., () => a)
}

এবং এটি কল

Thing.of(..., your_value)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.