স্কালার চটজলদি পদ্ধতি আমি এতক্ষণ বুঝতে পারি না


89

আমি কিছু স্লিক কাজ বোঝার চেষ্টা করি এবং এর জন্য কী প্রয়োজন।

এখানে এটি একটি উদাহরণ:

package models

case class Bar(id: Option[Int] = None, name: String)

object Bars extends Table[Bar]("bar") {
  def id = column[Int]("id", O.PrimaryKey, O.AutoInc)

  // This is the primary key column
  def name = column[String]("name")

  // Every table needs a * projection with the same type as the table's type parameter
  def * = id.? ~ name <>(Bar, Bar.unapply _)
}

কেউ আমাকে ব্যাখ্যা করতে পারেন যে *এখানে পদ্ধতির উদ্দেশ্য কী <>, কেন unapply? এবং প্রজেকশন কী - পদ্ধতি ~'এর উদাহরণটি ফেরত দেয় Projection2?

উত্তর:


198

[২] - জোড়া হয়েছে (এখনও অন্য) এ ব্যাখ্যা forcomprehensions

  1. *পদ্ধতি:

    এটি ডিফল্ট অভিক্ষেপটি ফিরিয়ে দেয় - যা আপনি বর্ণনা করেন:

    'সমস্ত কলাম (বা গণিত মান) আমি সাধারণত আগ্রহী'।

    আপনার টেবিলের বিভিন্ন ক্ষেত্র থাকতে পারে; আপনার কেবলমাত্র আপনার ডিফল্ট অভিক্ষেপের জন্য একটি উপসেট প্রয়োজন। ডিফল্ট অভিক্ষেপ অবশ্যই টেবিলের ধরণের পরামিতিগুলির সাথে মেলে।

    একবারে এটি এক নেওয়া যাক। <>স্টাফ ছাড়া , কেবল *:

    // First take: Only the Table Defintion, no case class:
    
    object Bars extends Table[(Int, String)]("bar") {
      def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
      def name = column[String]("name")
    
      def * = id ~ name // Note: Just a simple projection, not using .? etc
    }
    
    // Note that the case class 'Bar' is not to be found. This is 
    // an example without it (with only the table definition)
    

    এর মতো কেবল একটি সারণী সংজ্ঞা আপনাকে এ জাতীয় প্রশ্ন তৈরি করতে দেয়:

    implicit val session: Session = // ... a db session obtained from somewhere
    
    // A simple select-all:
    val result = Query(Bars).list   // result is a List[(Int, String)]
    

    এর মতো সাধারণ প্রশ্নের জন্য ডিফল্ট অভিক্ষেপ (Int, String)বাড়ে List[(Int, String)]

    // SELECT b.name, 1 FROM bars b WHERE b.id = 42;
    val q = 
       for (b <- Bars if b.id === 42) 
         yield (b.name ~ 1)
         // yield (b.name, 1) // this is also allowed: 
                              // tuples are lifted to the equivalent projection.
    

    কি ধরণের q? এটি Queryপ্রক্ষেপণের সাথে একটি (String, Int)। যখন প্রার্থনা, এটি একটি ফেরৎ Listএর (String, Int)অভিক্ষেপ অনুযায়ী tuples।

     val result: List[(String, Int)] = q.list
    

    এই ক্ষেত্রে, আপনি অভিক্ষেপ আপনি চান সংজ্ঞায়িত করেছেন yieldধারা forধী।

  2. এখন সম্পর্কে <>এবং Bar.unapply

    এটি ম্যাপেড প্রজেকশনস যাকে বলে তাকে সরবরাহ করে ।

    এখনও অবধি আমরা দেখেছি কীভাবে স্লিক আপনাকে স্কালায় ক্যোয়ারী প্রকাশ করতে সহায়তা করে যা কলামগুলির (বা গণিত মান) একটি অভিক্ষেপ দেয় ; যখন এই প্রশ্নের নির্বাহ সুতরাং আপনি ফলাফলের সারির চিন্তা করতে হবে একটি ক্যোয়ারী এর a Scala tuple যেমন । টিপলের ধরণটি সংজ্ঞায়িত প্রজেকশনটির সাথে মিলবে ( forপূর্ববর্তী উদাহরণের মতো আপনার বোধগম্যতার সাথে, ডিফল্ট *অভিক্ষেপ দ্বারা)। এই field1 ~ field2কারণটি Projection2[A, B]কোথায় এবং কী Aপ্রকারের একটি প্রক্ষেপণ দেয় ।field1Bfield2

    q.list.map {
      case (name, n) =>  // do something with name:String and n:Int
    }
    
    Queury(Bars).list.map {
      case (id, name) =>  // do something with id:Int and name:String 
    }
    

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

    (id ~ name)  // A projection
    
    // Assuming you have a Bar case class:
    case class Bar(id: Int, name: String) // For now, using a plain Int instead
                                          // of Option[Int] - for simplicity
    
    (id ~ name <> (Bar, Bar.unapply _)) // A MAPPED projection
    
    // Which lets you do:
    Query(Bars).list.map ( b.name ) 
    // instead of
    // Query(Bars).list.map { case (_, name) => name }
    
    // Note that I use list.map instead of mapResult just for explanation's sake.
    

    কিভাবে কাজ করে? <>একটি প্রক্ষেপণ নেয় Projection2[Int, String]এবং প্রকারভেদে একটি ম্যাপযুক্ত প্রজেকশন দেয় Bar। দুটি যুক্তি Bar, Bar.unapply _ স্লাইকে বলছে কীভাবে এই (Int, String)প্রজেকশনটি কেস ক্লাসে ম্যাপ করা উচিত।

    এটি দ্বিমুখী ম্যাপিং; Barকেস শ্রেণীর নির্মাতা, তাই এটি থেকে (id: Int, name: String)a এ যাওয়ার জন্য প্রয়োজনীয় তথ্য Bar। এবং unapply যদি আপনি এটি অনুমান করে থাকেন তবে এটি বিপরীতে।

    কোথা unapplyথেকে আসে? এটি কোনও সাধারণ কেস শ্রেণীর জন্য উপলব্ধ একটি স্ট্যান্ডার্ড পদ্ধতি - কেবল সংজ্ঞায়িত করা Barআপনাকে Bar.unapplyএমন একটি এক্সট্রাক্টর দেয় যা ফিরে পেতে ব্যবহার করা যেতে পারে idএবং nameএটি দিয়ে Barনির্মিত হয়েছিল:

    val bar1 = Bar(1, "one")
    // later
    val Bar(id, name) = bar1  // id will be an Int bound to 1,
                              // name a String bound to "one"
    // Or in pattern matching
    val bars: List[Bar] = // gotten from somewhere
    val barNames = bars.map {
      case Bar(_, name) => name
    }
    
    val x = Bar.unapply(bar1)  // x is an Option[(String, Int)]
    

    সুতরাং আপনার ডিফল্ট অভিক্ষেপ কেস ক্লাসে ম্যাপ করা যেতে পারে যা আপনি সবচেয়ে বেশি আশা করছেন:

    object Bars extends Table[Bar]("bar") {
      def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
      def name = column[String]("name")
      def * = id ~ name <>(Bar, Bar.unapply _)
    }
    

    অথবা আপনার কাছে প্রতি-ক্যোয়ারী থাকতে পারে:

    case class Baz(name: String, num: Int)
    
    // SELECT b.name, 1 FROM bars b WHERE b.id = 42;
    val q1 = 
       for (b <- Bars if b.id === 42) 
         yield (b.name ~ 1 <> (Baz, Baz.unapply _))
    

    এখানে ধরণ q1 একটি হল Queryএকটি সঙ্গে ম্যাপ করার অভিক্ষেপ Baz। যখন প্রার্থনা, এটি একটি ফেরৎ Listএর Bazবস্তু:

     val result: List[Baz] = q1.list
    
  3. পরিশেষে, একদিকে যেমন .?অফার অপশন লিফটিং - মানগুলি না করার স্ক্যালাল উপায়।

     (id ~ name)   // Projection2[Int, String] // this is just for illustration
     (id.? ~ name) // Projection2[Option[Int], String]
    

    মোড়ানো, যা আপনার মূল সংজ্ঞাটির সাথে সুন্দরভাবে কাজ করবে Bar:

    case class Bar(id: Option[Int] = None, name: String)
    
    // SELECT b.id, b.name FROM bars b WHERE b.id = 42;
    val q0 = 
       for (b <- Bars if b.id === 42) 
         yield (b.id.? ~ b.name <> (Bar, Bar.unapply _))
    
    
    q0.list // returns a List[Bar]
    
  4. স্লিক কীভাবে বোঝাপড়া ব্যবহার করে তার মন্তব্যের জবাবে for:

    একরকম, মনাদ সবসময় দেখাতে পরিচালনা করে এবং ব্যাখ্যাটির অংশ হওয়ার দাবি করে ...

    বোধগম্যতা কেবল সংগ্রহের জন্য নির্দিষ্ট নয়। এগুলি যে কোনও ধরণের মোনাডে ব্যবহৃত হতে পারে এবং সংগ্রহগুলি স্কালায় পাওয়া বিভিন্ন ধরণের মোনাদ ধরণের মধ্যে একটি মাত্র।

    তবে সংগ্রহগুলি পরিচিত হিসাবে, তারা ব্যাখ্যাটির জন্য একটি ভাল সূচনা পয়েন্ট তৈরি করে:

    val ns = 1 to 100 toList; // Lists for familiarity
    val result = 
      for { i <- ns if i*i % 2 == 0 } 
        yield (i*i)
    // result is a List[Int], List(4, 16, 36, ...)
    

    স্কালায়, বোঝার জন্য একটি পদ্ধতিটি (সম্ভবত নেস্টেড) পদ্ধতির কলগুলির জন্য সিনট্যাকটিক চিনি: উপরের কোডটি (কম বেশি) সমান:

    ns.filter(i => i*i % 2 == 0).map(i => i*i)
    

    মূলত, সাথে কাউকে filter, map, flatMap পদ্ধতি (অন্য কথায়, একটি একসংখ্যা ) একটি ব্যবহার করা যেতে পারে forধী স্থানে ns। একটি ভাল উদাহরণ অপশন মোনাড । এখানে আগের উদাহরণটি যেখানে একই forবিবৃতি Listপাশাপাশি উভয় Optionমনদেজে কাজ করে:

    // (1)
    val result = 
      for { 
        i <- ns          // ns is a List monad
        i2 <- Some(i*i)  // Some(i*i) is Option
          if i2 % 2 == 0 // filter
      } yield i2
    
    // Slightly more contrived example:
    def evenSqr(n: Int) = { // return the square of a number 
      val sqr = n*n         // only when the square is even
      if (sqr % 2 == 0) Some (sqr)
      else None
    }
    
    // (2)
    result = 
      for { 
        i <- ns  
        i2 <- evenSqr(i) // i2 may/maynot be defined for i!
      } yield i2
    

    শেষ উদাহরণে, রূপান্তরটি সম্ভবত এর মতো দেখাবে:

    // 1st example
    val result = 
      ns.flatMap(i => Some(i*i)).filter(i2 => i2 %2 ==0)
    
    // Or for the 2nd example
    result = 
      ns.flatMap(i => evenSqr(i)) 
    

    বাক্পটুতাপূর্ণ সালে প্রশ্নের পরমাণুসদৃশ্য - তারা কেবল বস্তু map, flatMapএবং filterপদ্ধতি। সুতরাং forবোধগম্যতা ( *পদ্ধতির ব্যাখ্যাতে প্রদর্শিত ) কেবল অনুবাদ করে:

    val q = 
      Query(Bars).filter(b => b.id === 42).map(b => b.name ~ 1)
    // Type of q is Query[(String, Int)]
    
    val r: List[(String, Int)] = q.list // Actually run the query
    

    যেহেতু আপনি দেখতে পারেন, flatMap, mapএবং filterএকটি জেনারেট করতে ব্যবহার করা হয় Queryবারংবার রূপান্তর দ্বারা Query(Bars) প্রতিটি আবাহন সঙ্গে filterএবং map। সংগ্রহের ক্ষেত্রে এই পদ্ধতিগুলি আসলে সংগ্রহটি পুনরাবৃত্তি করে এবং ফিল্টার করে তবে স্লিক এ সেগুলি এসকিউএল উত্পন্ন করতে ব্যবহৃত হয়। এখানে আরও বিশদ: স্কালা স্লিক কীভাবে জেডিবিসিতে স্কাল কোডটি অনুবাদ করে?


'1' ব্যাখ্যামূলক ব্লকে: 'ভ্যাল কিউ =' র্যাপিংকুই কি না তা স্পষ্ট নয়, কোডটি পড়ার সময় এটি একটি তালিকা <প্রজেক্ট 2> এর মতো দেখাচ্ছে। কীভাবে এটি ক্যোয়ারিতে রূপান্তরিত হয় ...? (এটি কীভাবে কাজ করে তা বোঝার জন্য আমি এখনও আপনার ব্যাখ্যা দিয়ে খেলছি this এর জন্য আপনাকে ধন্যবাদ!)
সেস

@ses - একটি (সামান্য দীর্ঘ) এই সম্পর্কে ব্যাখ্যা জোড়া হয়েছে ... এছাড়াও, এ বর্ণন stackoverflow.com/questions/13454347/monads-with-java-8/... - আমি বুঝলাম যে এটা প্রায় একই বিষয়বস্তু নেই।
ফয়েজ

যারা রহস্যজনক সংকলন ত্রুটিগুলি অনুভব করছেন তাদের কাছে নোট করুন, ফু ব্যবহার করুন? অপশন [টি] কলামগুলির জন্য বা আপনি মেলবন্ধ টাইপ করতে অসুবিধা পাবেন। ধন্যবাদ, ফয়েজ!
স্বেটিচে

4
এটি একটি দুর্দান্ত উত্তর ... এটি দুর্দান্ত হবে যদিও এটি স্লিক 3.0
আইএক্সএক্স

6

যেহেতু অন্য কেউ উত্তর দেয়নি, এটি আপনাকে শুরু করতে সহায়তা করতে পারে। আমি স্লিক খুব ভাল জানি না।

থেকে বাক্পটুতাপূর্ণ ডকুমেন্টেশন :

উত্তোলিত এম্বেডিং:

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

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


ook। এবং প্রজেকশন কেবল কলামগুলির উপস্থাপনা .. যেমন: চূড়ান্ত শ্রেণি প্রজেকশন 2 [টি 1, টি 2] (ওভাররাইড ভাল _1: কলাম [টি 1], ওভাররাইড ভাল _2: কলাম [টি 2]) প্রক্ষেপণের সাথে টুপল 2 (_1, _2) প্রসারিত করে [ টি 1, টি 2)] {..
সেস

এখন .. কীভাবে আসবেন: বারের 'প্রয়োগযোগ্য' পদ্ধতি আছে?
ses

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