স্কেল: একটি টাইপট্যাগ কী এবং আমি কীভাবে এটি ব্যবহার করব?


361

টাইপট্যাগগুলি সম্পর্কে আমি যা জানি তা হ'ল তারা কোনওরকমভাবে ম্যানিফেস্টগুলিকে প্রতিস্থাপন করেছে। ইন্টারনেটে তথ্য দুষ্প্রাপ্য এবং বিষয় সম্পর্কে আমাকে ভাল ধারণা দেয় না।

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


1
স্কালা ডকুমেন্টেশনের নীচের নিবন্ধে টাইপ ট্যাগগুলির কী এবং কেন, সেইসাথে আপনার কোডগুলিতে
btiernay

উত্তর:


563

একটি TypeTagরানার সময় (টাইপ মুছে ফেলা) এ স্ক্যালালের প্রকারগুলি মুছে ফেলা সমস্যা সমাধান করে। যদি আমরা করতে চাই

class Foo
class Bar extends Foo

def meth[A](xs: List[A]) = xs match {
  case _: List[String] => "list of strings"
  case _: List[Foo] => "list of foos"
}

আমরা সতর্কতা পেতে হবে:

<console>:23: warning: non-variable type argument String in type pattern List[String]↩
is unchecked since it is eliminated by erasure
         case _: List[String] => "list of strings"
                 ^
<console>:24: warning: non-variable type argument Foo in type pattern List[Foo]↩
is unchecked since it is eliminated by erasure
         case _: List[Foo] => "list of foos"
                 ^

এই সমস্যা সমাধানের জন্য ম্যানিফেষ্টগুলি স্কালার সাথে প্রবর্তিত হয়েছিল। তবে এগুলি পথ নির্ভর নির্ভর ধরণের মতো প্রচুর দরকারী প্রকারের প্রতিনিধিত্ব করতে না পারায় সমস্যা রয়েছে:

scala> class Foo{class Bar}
defined class Foo

scala> def m(f: Foo)(b: f.Bar)(implicit ev: Manifest[f.Bar]) = ev
warning: there were 2 deprecation warnings; re-run with -deprecation for details
m: (f: Foo)(b: f.Bar)(implicit ev: Manifest[f.Bar])Manifest[f.Bar]

scala> val f1 = new Foo;val b1 = new f1.Bar
f1: Foo = Foo@681e731c
b1: f1.Bar = Foo$Bar@271768ab

scala> val f2 = new Foo;val b2 = new f2.Bar
f2: Foo = Foo@3e50039c
b2: f2.Bar = Foo$Bar@771d16b9

scala> val ev1 = m(f1)(b1)
warning: there were 2 deprecation warnings; re-run with -deprecation for details
ev1: Manifest[f1.Bar] = Foo@681e731c.type#Foo$Bar

scala> val ev2 = m(f2)(b2)
warning: there were 2 deprecation warnings; re-run with -deprecation for details
ev2: Manifest[f2.Bar] = Foo@3e50039c.type#Foo$Bar

scala> ev1 == ev2 // they should be different, thus the result is wrong
res28: Boolean = true

সুতরাং, এগুলি টাইপট্যাগগুলি দ্বারা প্রতিস্থাপিত হয় , যা উভয়ই ব্যবহার করতে অনেক সহজ এবং নতুন প্রতিচ্ছবি এপিআইতে ভালভাবে সংহত করা হয়। তাদের সাথে আমরা পথ-নির্ভর-প্রকারগুলি সম্পর্কে মার্জিতভাবে উপরের সমস্যাটি সমাধান করতে পারি:

scala> def m(f: Foo)(b: f.Bar)(implicit ev: TypeTag[f.Bar]) = ev
m: (f: Foo)(b: f.Bar)(implicit ev: reflect.runtime.universe.TypeTag[f.Bar])↩
reflect.runtime.universe.TypeTag[f.Bar]

scala> val ev1 = m(f1)(b1)
ev1: reflect.runtime.universe.TypeTag[f1.Bar] = TypeTag[f1.Bar]

scala> val ev2 = m(f2)(b2)
ev2: reflect.runtime.universe.TypeTag[f2.Bar] = TypeTag[f2.Bar]

scala> ev1 == ev2 // the result is correct, the type tags are different
res30: Boolean = false

scala> ev1.tpe =:= ev2.tpe // this result is correct, too
res31: Boolean = false

টাইপ প্যারামিটারগুলি পরীক্ষা করার জন্য এগুলি ব্যবহার করা সহজ:

import scala.reflect.runtime.universe._

def meth[A : TypeTag](xs: List[A]) = typeOf[A] match {
  case t if t =:= typeOf[String] => "list of strings"
  case t if t <:< typeOf[Foo] => "list of foos"
}

scala> meth(List("string"))
res67: String = list of strings

scala> meth(List(new Bar))
res68: String = list of foos

এই মুহুর্তে, সাম্যতা পরীক্ষার জন্য =:=(ধরণের সাম্যতা) এবং <:<(সাব টাইপ সম্পর্ক) বোঝা অত্যন্ত গুরুত্বপূর্ণ । ব্যবহার না না ==বা !=, যদি না আপনি একেবারে জানেন তোমরা যা কর:

scala> typeOf[List[java.lang.String]] =:= typeOf[List[Predef.String]]
res71: Boolean = true

scala> typeOf[List[java.lang.String]] == typeOf[List[Predef.String]]
res72: Boolean = false

পরেরটি কাঠামোগত সাম্যের জন্য যাচাই করে, যা প্রায়শই করা উচিত নয় কারণ এটি উপসর্গের মতো বিষয়গুলির উদাহরণ দেয় না (উদাহরণস্বরূপ)।

TypeTagসম্পূর্ণরূপে সংকলক উত্পাদিত, এর অর্থ এই যে সংকলকটি TypeTagযখন এমন পদ্ধতি প্রত্যাশিত একটি পদ্ধতি তৈরি করে এবং পূরণ করে TypeTag। ট্যাগের তিনটি পৃথক রূপ রয়েছে:

ClassTagবিকল্প ClassManifestযেখানে TypeTagকমবেশি প্রতিস্থাপন হয় Manifest

প্রাক্তন জেনেরিক অ্যারেগুলির সাথে পুরোপুরি কাজ করতে দেয়:

scala> import scala.reflect._
import scala.reflect._

scala> def createArr[A](seq: A*) = Array[A](seq: _*)
<console>:22: error: No ClassTag available for A
       def createArr[A](seq: A*) = Array[A](seq: _*)
                                           ^

scala> def createArr[A : ClassTag](seq: A*) = Array[A](seq: _*)
createArr: [A](seq: A*)(implicit evidence$1: scala.reflect.ClassTag[A])Array[A]

scala> createArr(1,2,3)
res78: Array[Int] = Array(1, 2, 3)

scala> createArr("a","b","c")
res79: Array[String] = Array(a, b, c)

ClassTag রানটাইমে টাইপ তৈরি করতে প্রয়োজনীয় তথ্য সরবরাহ করে (যা টাইপগুলি মুছে ফেলা হয়):

scala> classTag[Int]
res99: scala.reflect.ClassTag[Int] = ClassTag[int]

scala> classTag[Int].runtimeClass
res100: Class[_] = int

scala> classTag[Int].newArray(3)
res101: Array[Int] = Array(0, 0, 0)

scala> classTag[List[Int]]
res104: scala.reflect.ClassTag[List[Int]] =ClassTag[class scala.collection.immutable.List]

যেহেতু উপরে কেউ দেখতে পাচ্ছে, তারা প্রকার মুছে ফেলার বিষয়ে চিন্তা করে না, অতএব যদি কেউ "পূর্ণ" প্রকারগুলি চায় তবে TypeTagএটি ব্যবহার করা উচিত:

scala> typeTag[List[Int]]
res105: reflect.runtime.universe.TypeTag[List[Int]] = TypeTag[scala.List[Int]]

scala> typeTag[List[Int]].tpe
res107: reflect.runtime.universe.Type = scala.List[Int]

scala> typeOf[List[Int]]
res108: reflect.runtime.universe.Type = scala.List[Int]

scala> res107 =:= res108
res109: Boolean = true

এক দেখতে পারেন, পদ্ধতি tpeএর TypeTagএকটি পূর্ণ ফলাফল Type, যা একই আমরা যখন পাবেন typeOfবলা হয়। অবশ্যই, এটি উভয়ই ব্যবহার করা সম্ভব ClassTagএবং TypeTag:

scala> def m[A : ClassTag : TypeTag] = (classTag[A], typeTag[A])
m: [A](implicit evidence$1: scala.reflect.ClassTag[A],implicit evidence$2: reflect.runtime.universe.TypeTag[A])(scala.reflect.ClassTag[A], reflect.runtime.universe.TypeTag[A])

scala> m[List[Int]]
res36: (scala.reflect.ClassTag[List[Int]],↩
        reflect.runtime.universe.TypeTag[List[Int]]) =(scala.collection.immutable.List,TypeTag[scala.List[Int]])

এখন বাকী প্রশ্ন হ'ল বোধটি কী WeakTypeTag? সংক্ষেপে, TypeTagএকটি কংক্রিট ধরণের প্রতিনিধিত্ব করে (এর অর্থ এটি কেবল পুরোপুরি তাত্ক্ষণিক ধরণের WeakTypeTagঅনুমতি দেয় ) যেখানে কেবল কোনও প্রকারের অনুমতি দেয়। বেশিরভাগ সময়ই কোনটি যত্ন করে না যা কোনটি (যার অর্থ TypeTagব্যবহার করা উচিত), তবে উদাহরণস্বরূপ, যখন ম্যাক্রোগুলি ব্যবহার করা হয় যা জেনেরিক ধরণের সাথে কাজ করা উচিত তাদের প্রয়োজন:

object Macro {
  import language.experimental.macros
  import scala.reflect.macros.Context

  def anymacro[A](expr: A): String = macro __anymacro[A]

  def __anymacro[A : c.WeakTypeTag](c: Context)(expr: c.Expr[A]): c.Expr[A] = {
    // to get a Type for A the c.WeakTypeTag context bound must be added
    val aType = implicitly[c.WeakTypeTag[A]].tpe
    ???
  }
}

তাহলে এক প্রতিস্থাপন WeakTypeTagসঙ্গে TypeTagএকটি ত্রুটি নিক্ষিপ্ত হয়:

<console>:17: error: macro implementation has wrong shape:
 required: (c: scala.reflect.macros.Context)(expr: c.Expr[A]): c.Expr[String]
 found   : (c: scala.reflect.macros.Context)(expr: c.Expr[A])(implicit evidence$1: c.TypeTag[A]): c.Expr[A]
macro implementations cannot have implicit parameters other than WeakTypeTag evidences
             def anymacro[A](expr: A): String = macro __anymacro[A]
                                                      ^

এই প্রশ্নের মধ্যে পার্থক্য সম্পর্কে আরও বিশদ ব্যাখ্যার জন্য TypeTagএবং WeakTypeTagদেখুন: স্কালার ম্যাক্রোস: "অমীমাংসিত টাইপ পরামিতি থাকা টাইপ টি থেকে টাইপট্যাগ তৈরি করতে পারে না"

স্কালার অফিসিয়াল ডকুমেন্টেশন সাইটে প্রতিবিম্বের জন্য একটি গাইড রয়েছে ।


19
আপনার উত্তরের জন্য ধন্যবাদ! কিছু মন্তব্য: 1) ==ধরণের জন্য কাঠামোগত সাম্য প্রতিনিধিত্ব করে, সমতা উল্লেখ করে না। =:=অ্যাকাউন্টের ধরণের সমতুল্যতা গ্রহণ করুন (এমনকী অ-স্পষ্ট যেমন যেমন বিভিন্ন আয়না থেকে আসা উপসর্গের সমতুল্য), ২) উভয়ই TypeTagএবং AbsTypeTagআয়নাভিত্তিক। পার্থক্য হল যে TypeTagশুধুমাত্র সম্পূর্ণরূপে instantiated অনুমতি দেয় ধরনের, 3) একটি বিস্তারিত ব্যাখ্যা এখানে (অর্থাত কোনো ধরনের পরামিতি বা রেফারেন্স বিমূর্ত টাইপ সদস্যদের ছাড়াই): stackoverflow.com/questions/12093752
ইউজিন Burmako

10
4) ম্যানিফেস্টগুলিতে প্রচুর দরকারী ধরণের উপস্থাপন করতে সক্ষম না হওয়ার সমস্যা রয়েছে। মূলত তারা কেবল টাইপ রেফগুলিই প্রকাশ করতে পারে (যেমন সরল প্রকারের মতো Intএবং জেনেরিক ধরণের যেমন List[Int]) যেমন স্কেল প্রকারগুলি যেমন উদ্বোধন, পথ-নির্ভর ধরণের, অস্তিত্বহীন, টীকাযুক্ত প্রকারগুলি বাদ দেয়। এছাড়াও উদ্ভাস একটি বল্টু, সুতরাং তারা যে বিস্তৃত জ্ঞানকে
সংকলকটি

9
৫) বিপরীতে টাইপ ট্যাগগুলি "আরও ভাল সংহত" হয় না, তারা কেবলমাত্র নতুন প্রতিবিম্ব এপিআইয়ের সাথে একত্রিত হয় (যা কোনও কিছুর সাথে সংহত হয় না তার বিপরীতে)। এই ধরনের ট্যাগ কম্পাইলার, যেমন করতে নির্দিষ্ট রূপ অ্যাক্সেস প্রদান করে Types.scala(কোড জানে যে কিভাবে ধরনের একসাথে কাজ করার সমর্থিত এর 7kloc), Symbols.scala(কোডের 3kloc যে জানেন কিভাবে প্রতীক টেবিল কাজ), ইত্যাদি
ইউজিন Burmako

9
6) ClassTagহুবহু ড্রপ-ইন প্রতিস্থাপন ClassManifest, যেখানে TypeTagকম-বেশি বিকল্প রয়েছে Manifest। কম বেশি, কারণ: 1) টাইপ ট্যাগগুলি ইরেজ বহন করে না, 2) ম্যানিফাইস্টগুলি একটি বড় হ্যাক, এবং আমরা টাইপ ট্যাগগুলির সাথে এর আচরণ অনুকরণ করে ছেড়ে দিয়েছি। আপনার মুছে ফেলা এবং প্রকার উভয়ই প্রয়োজন হলে ক্লাসট্যাগ এবং টাইপট্যাগ উভয় প্রসঙ্গের সীমা ব্যবহার করে # 1 স্থির করা যেতে পারে এবং একটি সাধারণত # 2 সম্পর্কে চিন্তা করে না, কারণ সমস্ত হ্যাকগুলি ফেলে দেওয়া এবং পূর্ণাঙ্গ প্রতিচ্ছবি API ব্যবহার করা সম্ভব হয়ে ওঠে পরিবর্তে.
ইউজিন বার্মাকো

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