স্কালায় অন্তর্নিহিত বোঝা


308

আমি স্কালা প্লেফ্রেমওয়ার্ক টিউটোরিয়ালটি দিয়ে আমার পথ তৈরি করছিলাম এবং আমি কোডটির এই স্নিপেটটি পেয়েছিলাম যা আমাকে বিস্মিত করেছিল:

def newTask = Action { implicit request =>
taskForm.bindFromRequest.fold(
        errors => BadRequest(views.html.index(Task.all(), errors)),
        label => {
          Task.create(label)
          Redirect(routes.Application.tasks())
        } 
  )
}

তাই আমি তদন্তের সিদ্ধান্ত নিয়েছি এবং এই পোস্টটি জুড়ে এসেছি ।

আমি এখনও এটি পাই না।

এর মধ্যে পার্থক্য কী:

implicit def double2Int(d : Double) : Int = d.toInt

এবং

def double2IntNonImplicit(d : Double) : Int = d.toInt

সুস্পষ্ট সত্য ব্যতীত তাদের পৃথক পদ্ধতির নাম রয়েছে।

আমার কখন ব্যবহার করা উচিত implicitএবং কেন?


উত্তর:


391

আমি নীচে ফাঁসির মূল ব্যবহারের ঘটনাগুলি ব্যাখ্যা করব, তবে আরও তথ্যের জন্য স্কালায় প্রোগ্রামিং সম্পর্কিত প্রাসঙ্গিক দেখুন ।

অন্তর্নিহিত পরামিতি

কোনও পদ্ধতির চূড়ান্ত প্যারামিটার তালিকা চিহ্নিত করা যায় implicit, যার অর্থ মানগুলি যে প্রসঙ্গে বলা হয় সেখান থেকে নেওয়া হবে। সুযোগে যদি সঠিক ধরণের কোনও অন্তর্নির্মিত মান না থাকে তবে এটি সংকলন করবে না। যেহেতু অন্তর্নিহিত মানটি একটি একক মানের সমাধান করতে এবং সংঘর্ষ এড়ানোর জন্য সমাধান করা উচিত, তাই ধরণের ধরণের উদ্দেশ্যটি তার উদ্দেশ্যে নির্দিষ্ট করে তোলা ভাল ধারণা, উদাহরণস্বরূপ আপনার অন্তর্নিহিত সন্ধানের জন্য আপনার পদ্ধতিগুলির প্রয়োজন হবে না Int!

উদাহরণ:

  // probably in a library
class Prefixer(val prefix: String)
def addPrefix(s: String)(implicit p: Prefixer) = p.prefix + s

  // then probably in your application
implicit val myImplicitPrefixer = new Prefixer("***")
addPrefix("abc")  // returns "***abc"

অন্তর্নিহিত রূপান্তর

সংকলক যখন প্রসঙ্গের জন্য ভুল ধরণের একটি অভিব্যক্তি খুঁজে পায়, তখন এটি Functionকোনও প্রকারের অন্তর্নিহিত মানের সন্ধান করবে যা এটি টাইপচেককে অনুমতি দেবে। সুতরাং যদি কোনও Aপ্রয়োজন হয় এবং এটি সন্ধান করে তবে Bএটি B => Aসুযোগের প্রকারের অন্তর্নিহিত মানের সন্ধান করবে (এটি অন্য কিছু জায়গার মতো Bএবং Aসহযোগী বস্তুগুলির মধ্যেও উপস্থিত রয়েছে, যদি এটি উপস্থিত থাকে তবে এটি পরীক্ষা করে)। যেহেতু defগুলি Functionবস্তুগুলিতে "ইটা-প্রসারিত" হতে পারে, তাই একটি implicit def xyz(arg: B): Aকাজও করবে।

সুতরাং আপনার পদ্ধতির মধ্যে পার্থক্য হ'ল চিহ্নিত implicitচিহ্নিতটি আপনার জন্য সংকলক দ্বারা সন্নিবেশ করা হবে যখন একটি Doubleপাওয়া যায় তবে একটি Intপ্রয়োজনীয় হয়।

implicit def doubleToInt(d: Double) = d.toInt
val x: Int = 42.0

হিসাবে একই কাজ করবে

def doubleToInt(d: Double) = d.toInt
val x: Int = doubleToInt(42.0)

দ্বিতীয়টিতে আমরা ম্যানুয়ালি রূপান্তর প্রবেশ করিয়েছি; প্রথমটিতে সংকলক স্বয়ংক্রিয়ভাবে একই কাজ করেছিল। বাম হাতের ধরণের টিকা রচনার কারণে রূপান্তরটি প্রয়োজনীয়।


প্লে থেকে আপনার প্রথম স্নিপেট সম্পর্কিত:

প্লে ডকুমেন্টেশন ( এপিআই ডকসও দেখুন ) থেকে এই পৃষ্ঠায় ক্রিয়াগুলি ব্যাখ্যা করা হয়েছে । আপনি ব্যবহার করছেন

apply(block: (Request[AnyContent])Result): Action[AnyContent]

উপর Actionবস্তু (যা একই নামের বৈশিষ্ট্য থেকে সহচর)।

সুতরাং আমাদের যুক্তি হিসাবে একটি ফাংশন সরবরাহ করতে হবে যা ফর্মটিতে আক্ষরিক হিসাবে লেখা যেতে পারে

request => ...

একটি ফাংশন আক্ষরিক ক্ষেত্রে, এর পূর্বে অংশটি =>একটি মান ঘোষণা এবং implicitআপনি চাইলে চিহ্নিত করতে পারেন, যেমন অন্য কোনও valঘোষণার মতো। এখানে, চেক টাইপ করার জন্য এটি চিহ্নিত করতে হবে request নাimplicit , তবে এটি করার মাধ্যমে এটি কোনও পদ্ধতিগুলির জন্য এটির প্রয়োজনের জন্য অন্তর্ভুক্ত মূল্য হিসাবে উপলব্ধ হবে (এবং অবশ্যই এটি স্পষ্টভাবেও ব্যবহার করা যেতে পারে) । এই বিশেষ ক্ষেত্রে, এটি করা হয়েছে কারণ ফর্ম শ্রেণিতে bindFromRequestপদ্ধতিটির জন্য একটি অন্তর্নিহিত যুক্তি প্রয়োজন।Request


12
প্রতিক্রিয়ার জন্য আপনাকে ধন্যবাদ. 21 অধ্যায়ের লিঙ্কটি সত্যিই দুর্দান্ত। সন্তুষ্ট.
ক্লাইভ

14
কেবল এটি যুক্ত করতে, নীচের ভিডিওটি স্কেল ইউটিউব.com/watch?v =
শক্তি

ঝাঁপ দাও 24:25 উপরের ভিডিওতে (যে 55 মিনিট মাধ্যমে শুনতে চাই না জন্য)
papigee

36

সতর্কতা: কটূক্তি যুক্তিসঙ্গতভাবে রয়েছে! YMMV ...

লুইগির উত্তর সম্পূর্ণ এবং সঠিক। আপনি কীভাবে মহিমান্বিতভাবে অতিরিক্ত ব্যবহার করতে পারেন তার একটি উদাহরণ সহ এটি কেবলমাত্র এটি প্রসারিত করতে হবে প্রভাবকে যেমন স্ক্যালাল প্রকল্পগুলিতে প্রায়শই ঘটে। প্রকৃতপক্ষে প্রায়শই আপনি সম্ভবত এটি "সেরা অনুশীলন" গাইডগুলির মধ্যে একটিতেও খুঁজে পেতে পারেন ।

object HelloWorld {
  case class Text(content: String)
  case class Prefix(text: String)

  implicit def String2Text(content: String)(implicit prefix: Prefix) = {
    Text(prefix.text + " " + content)
  }

  def printText(text: Text): Unit = {
    println(text.content)
  }

  def main(args: Array[String]): Unit = {
    printText("World!")
  }

  // Best to hide this line somewhere below a pile of completely unrelated code.
  // Better yet, import its package from another distant place.
  implicit val prefixLOL = Prefix("Hello")
}

1
হা হা। হাস্যরসের ভাল ধারণা।
Det

1
আমি কৌতুক প্রশংসা করি। এই ধরণের জিনিসটি আমি বহু বছর আগে স্কেলা শেখার চেষ্টা বন্ধ করে দেওয়ার একটি কারণ এবং কেবল এখন এটিতে ফিরে আসছি। আমি কখনই নিশ্চিত ছিলাম না যে কোডটি আমি দেখছিলাম তাতে কিছু (অনেক) বোঝা কোথায় থেকে আসছিল।
মেলস্টন

7

কেন এবং কখন আপনার requestহিসাবে প্যারামিটারটি চিহ্নিত করা উচিতimplicit :

আপনার ক্রিয়াকলাপের শরীরে আপনি যে কয়েকটি পদ্ধতি ব্যবহার করবেন সেগুলির একটি অন্তর্নিহিত প্যারামিটার তালিকা রয়েছে যেমন, উদাহরণস্বরূপ, ফর্ম.স্কালা একটি পদ্ধতির সংজ্ঞা দেয়:

def bindFromRequest()(implicit request: play.api.mvc.Request[_]): Form[T] = { ... }

আপনি অগত্যা এটি কল করবেন বলে myForm.bindFromRequest()আপনি অগত্যা এটি লক্ষ্য করবেন না আপনাকে স্পষ্টভাবে অন্তর্নিহিত যুক্তি সরবরাহ করতে হবে না। না, আপনি ছেড়ে কম্পাইলার প্রত্যেক সময় এটা একটা পদ্ধতি কল যে অনুরোধের একটি দৃষ্টান্ত প্রয়োজন জুড়ে আসে মধ্যে পাস কোনো বৈধ প্রার্থী বস্তুর জন্য দেখুন। যেহেতু আপনার কাছে একটি অনুরোধ উপলব্ধ আছে, আপনার যা করা দরকার তা এটি হিসাবে চিহ্নিত করা markimplicit

আপনি স্পষ্টতই এটি অন্তর্নিহিত জন্য উপলব্ধ হিসাবে চিহ্নিত করুন ব্যবহারের ।

আপনি সংকলকটি ইঙ্গিত করেছেন যে প্লে ফ্রেমওয়ার্কের মাধ্যমে প্রেরিত অনুরোধের অবজেক্টটি ব্যবহার করার জন্য এটি "ঠিক আছে" (যে আমরা "অনুরোধ" নাম দিয়েছি তবে যেখানে প্রয়োজন সেখানে "আর" বা "রেক" ব্যবহার করতে পারতাম), "স্লাই" তে ।

myForm.bindFromRequest()

এটা দেখ? এটি সেখানে নেই, তবে এটি আছে নাকি!

এটি আপনার প্রয়োজন মতো স্থানে ম্যানুয়ালি স্লট না করেই ঘটে (তবে আপনি এটি স্পষ্টভাবে পাস করতে পারেন , আপনি যদি চান তবে তা চিহ্নিত করা হয়েছে implicitবা না তা নয়):

myForm.bindFromRequest()(request)

অন্তর্নিহিত যেমন উপলক্ষে ছাড়া, আপনি হবে আছে উপরে না। এটিকে অন্তর্নিহিত হিসাবে চিহ্নিত করা আপনার দরকার নেই।

আপনি কখন অনুরোধটি চিহ্নিত করবেন implicit? আপনার যদি কেবল অনুরোধের উদাহরণের প্রত্যাশা করে এমন একটি পরামিতি পরামিতি তালিকা ঘোষণা করে এমন পদ্ধতি ব্যবহার করে থাকেন তবে আপনার কেবল সত্যই প্রয়োজন । তবে এটি সহজ রাখতে আপনি অনুরোধটি implicit সর্বদা চিহ্নিত করার অভ্যাসে প্রবেশ করতে পারেন । এইভাবে আপনি কেবল সুন্দর প্রসার কোড লিখতে পারেন।


2
"এইভাবে আপনি কেবল সুন্দর বর্ণের কোড লিখতে পারেন।" বা, যেমন @ ড্যানিয়েলডিনিজগুলি উল্লেখ করেছে, খুব সুন্দরভাবে কোডটি বিভ্রান্ত করেছে। কোনও অন্তর্নিহিত কোথা থেকে আসছেন তা সন্ধান করা সত্যিকারের ব্যথা হতে পারে এবং যদি আপনি সতর্ক না হন তবে তারা আসলে কোডটি পড়া এবং বজায় রাখা আরও শক্ত করে তুলতে পারে।
মেলস্টন

7

স্কেলে অন্তর্নিহিত কাজগুলি :

পরিবর্তক

প্যারামিটার মান ইনজেক্টর

ইমপ্লিটের ব্যবহারের 3 প্রকার রয়েছে

  1. সুস্পষ্টভাবে রূপান্তর টাইপ করুন : এটি ত্রুটি উত্পাদনের ক্ষেত্রে ত্রুটিটিকে উদ্দেশ্যমূলক প্রকারে রূপান্তর করে

    ভাল এক্স: স্ট্রিং = "1"

    ভাল y: ইন্ট = এক্স

স্ট্রিং ইন্টের সাব টাইপ নয় , সুতরাং লাইন ২-এ ত্রুটি ঘটে the ত্রুটিটি সমাধানের জন্য কমপাইলার স্কোপটিতে এমন একটি পদ্ধতি সন্ধান করবে যা অন্তর্নিহিত কীওয়ার্ড রয়েছে এবং একটি স্ট্রিংকে আর্গুমেন্ট হিসাবে গ্রহণ করে এবং একটি আন্তঃকে ফেরত দেয়

সুতরাং

implicit def z(a:String):Int = 2

val x :String = "1"

val y:Int = x // compiler will use z here like val y:Int=z(x)

println(y) // result 2  & no error!
  1. সুস্পষ্টভাবে রিসিভার রূপান্তর : আমরা সাধারণত রিসিভার কল বস্তুর বৈশিষ্ট্য দ্বারা, যেমন। পদ্ধতি বা ভেরিয়েবল। সুতরাং কোনও প্রাপকের দ্বারা যে কোনও সম্পত্তি কল করতে সম্পত্তি অবশ্যই সেই প্রাপকের শ্রেণি / অবজেক্টের সদস্য হতে হবে।

    class Mahadi{
    
    val haveCar:String ="BMW"
    
    }

    class Johnny{

    val haveTv:String = "Sony"

    }

   val mahadi = new Mahadi



   mahadi.haveTv // Error happening

এখানে mahadi.haveTv একটি ত্রুটি তৈরি করবে। কারণ Scala কম্পাইলার প্রথম দেখবে haveTv করার সম্পত্তি Mahadi রিসিভার। এটি পাবেন না। দ্বিতীয়ত এটি স্কোলে এমন পদ্ধতি আবিষ্কার করবে যাতে অন্তর্নিহিত কীওয়ার্ড থাকবে যা মহাদী অবজেক্টকে যুক্তি হিসাবে গ্রহণ করে এবং জনি অবজেক্টকে ফিরিয়ে দেয় । তবে এটি এখানে নেই। সুতরাং এটি ত্রুটি তৈরি করবে । তবে নিম্নলিখিতটি ঠিক আছে।

class Mahadi{

val haveCar:String ="BMW"

}

class Johnny{

val haveTv:String = "Sony"

}

val mahadi = new Mahadi

implicit def z(a:Mahadi):Johnny = new Johnny

mahadi.haveTv // compiler will use z here like new Johnny().haveTv

println(mahadi.haveTv)// result Sony & no error
  1. সুস্পষ্টভাবে প্যারামিটার ইঞ্জেকশন : আমরা যদি কোনও পদ্ধতি কল করি এবং এর পরামিতি মানটি পাস না করি তবে এটি ত্রুটি ঘটবে। স্কেল সংকলক এর মতো কাজ করে - প্রথমে মান পাস করার চেষ্টা করবে তবে এটি প্যারামিটারের জন্য কোনও সরাসরি মান পাবে না।

    def x(a:Int)= a
    
    x // ERROR happening

এটি কোনো জন্য চেহারা হবে দ্বিতীয় যদি প্যারামিটার কোনো অন্তর্নিহিত শব্দ রয়েছে Val মধ্যে সুযোগ যা আছে একই ধরনের মান। না পেলে ত্রুটি ঘটবে।

def x(implicit a:Int)= a

x // error happening here

Slove করার এই সমস্যা কম্পাইলার একটি জন্য চেহারা হবে অন্তর্নিহিত Val থাকার ইন্টারঅ্যাক্টিভ ধরণ কারণ পরামিতি একটি হয়েছে অন্তর্নিহিত শব্দ

def x(implicit a:Int)=a

implicit val z:Int =10

x // compiler will use implicit like this x(z)
println(x) // will result 10 & no error.

আরেকটি উদাহরণ:

def l(implicit b:Int)

def x(implicit a:Int)= l(a)

আমরা এটি যেমন লিখতে পারি-

def x(implicit a:Int)= l

কারণ টি অন্তর্নিহিত পরামিতি এবং সুযোগ পদ্ধতি এক্স লাশ , একটি হল অন্তর্নিহিত স্থানীয় পরিবর্তনশীল ( পরামিতি স্থানীয় ভেরিয়েবল ) একটি যার প্যারামিটার এক্স , তাই এক্স লাশ পদ্ধতি পদ্ধতি স্বাক্ষর L'গুলি অন্তর্নিহিত যুক্তি মান হয় দায়ের এক্স পদ্ধতি স্থানীয় অন্তর্নিহিত পরিবর্তনশীল (প্যারামিটার) aপরোক্ষভাবে

সুতরাং

 def x(implicit a:Int)= l

এই মত সংকলক হবে

def x(implicit a:Int)= l(a)

আরেকটি উদাহরণ:

def c(implicit k:Int):String = k.toString

def x(a:Int => String):String =a

x{
x => c
}

এটা, ত্রুটি কারণ কারণ হবে মধ্যে এক্স {এক্স => C} স্পষ্টভাবে মান-ক্ষণস্থায়ী আর্গুমেন্ট বা অন্তর্নিহিত Val দরকার সুযোগ

সুতরাং আমরা যখন পদ্ধতিটি এক্স বলি তখন আমরা ফাংশনটির আক্ষরিক পরামিতিটি স্পষ্টভাবে অন্তর্নিহিত করতে পারি

x{
implicit x => c // the compiler will set the parameter of c like this c(x)
}

এটি প্লে-ফ্রেমওয়ার্কের ক্রিয়া পদ্ধতিতে ব্যবহৃত হয়েছে

in view folder of app the template is declared like
@()(implicit requestHreader:RequestHeader)

in controller action is like

def index = Action{
implicit request =>

Ok(views.html.formpage())  

}

আপনি যদি স্পষ্টভাবে নিখুঁতভাবে অনুরোধের প্যারামিটারটির উল্লেখ না করেন তবে আপনাকে অবশ্যই লিখিত থাকতে হবে-

def index = Action{
request =>

Ok(views.html.formpage()(request))  

}

4

এছাড়াও, উপরের ক্ষেত্রে only oneনিখুঁত ফাংশন থাকা উচিত যার প্রকার double => Int। অন্যথায়, সংকলকটি বিভ্রান্ত হয়ে পড়ে এবং সঠিকভাবে সংকলন করে না।

//this won't compile

implicit def doubleToInt(d: Double) = d.toInt
implicit def doubleToIntSecond(d: Double) = d.toInt
val x: Int = 42.0

0

স্কেলায় ইমপ্লিটগুলির একটি খুব প্রাথমিক উদাহরণ example

অন্তর্নিহিত পরামিতি :

val value = 10
implicit val multiplier = 3
def multiply(implicit by: Int) = value * by
val result = multiply // implicit parameter wiil be passed here
println(result) // It will print 30 as a result

দ্রষ্টব্য: এখানে multiplierস্পষ্টতই ফাংশনটিতে স্থান দেওয়া হবে multiply। ফাংশন কলের অনুপস্থিত প্যারামিটারগুলি বর্তমান স্কোপটিতে টাইপ করে দেখা হবে অর্থাত্ স্কোপটিতে ইন্ট টাইপের কোনও অন্তর্ভুক্ত ভেরিয়েবল না থাকলে কোডটি সংকলন করবে না।

অন্তর্নিহিত রূপান্তর :

implicit def convert(a: Double): Int = a.toInt
val res = multiply(2.0) // Type conversions with implicit functions
println(res)  // It will print 20 as a result

দ্রষ্টব্য: যখন আমরা multiplyফাংশনটিকে একটি দ্বৈত মানকে বলি , তখন সংকলক বর্তমান স্কোপটিতে রূপান্তর অন্তর্নিহিত ফাংশনটি সন্ধান করার চেষ্টা করবে, যা রূপান্তর Intকরে Double(হিসাবে ফাংশন multiplyগ্রহণযোগ্য Intপ্যারামিটার হিসাবে )। যদি কোনও অন্তর্নিহিত convertফাংশন না থাকে তবে সংকলক কোডটি সংকলন করবে না।


0

আপনার মত আমার কাছেও একই প্রশ্ন ছিল এবং আমার মনে হয় যে কয়েকটি সহজ উদাহরণ দিয়ে আমি এটি কীভাবে বুঝতে শুরু করেছি তা ভাগ করে নেওয়া উচিত (নোট করুন যে এটি কেবল সাধারণ ব্যবহারের ক্ষেত্রে কভার করে)।

স্কালায় দুটি ব্যবহারের সাধারণ ব্যবহার রয়েছে implicit

  • এটি একটি ভেরিয়েবলে ব্যবহার করা
  • এটি একটি ফাংশনে ব্যবহার করে

উদাহরণগুলি নিম্নরূপ

এটি একটি ভেরিয়েবলে ব্যবহার করা । আপনি দেখতে পাচ্ছেন, implicitকীওয়ার্ডটি যদি সর্বশেষ প্যারামিটার তালিকায় ব্যবহৃত হয়, তবে নিকটতম ভেরিয়েবল ব্যবহার করা হবে।

// Here I define a class and initiated an instance of this class
case class Person(val name: String)
val charles: Person = Person("Charles")

// Here I define a function
def greeting(words: String)(implicit person: Person) = person match {
  case Person(name: String) if name != "" => s"$name, $words"
    case _ => "$words"
}

greeting("Good morning") // Charles, Good moring

val charles: Person = Person("")
greeting("Good morning") // Good moring

এটি একটি ফাংশনে ব্যবহার করে । আপনি দেখতে পাচ্ছেন যে, যদি implicitফাংশনে ব্যবহৃত হয় তবে নিকটতম ধরণের রূপান্তর পদ্ধতিটি ব্যবহৃত হবে।

val num = 10 // num: Int (of course)

// Here I define a implicit function
implicit def intToString(num: Int) = s"$num -- I am a String now!"

val num = 10 // num: Int (of course). Nothing happens yet.. Compiler believes you want 10 to be an Int

// Util...
val num: String = 10 // Compiler trust you first, and it thinks you have `implicitly` told it that you had a way to covert the type from Int to String, which the function `intToString` can do!
// So num is now actually "10 -- I am a String now!"
// console will print this -> val num: String = 10 -- I am a String now!

আশা করি এটি সাহায্য করতে পারে।

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