আমি রানটাইমে একটি ভেরিয়েবলের ধরণ পেতে চাই। আমি এটা কিভাবে করবো?
উত্তর:
সুতরাং, কঠোরভাবে বলতে গেলে, "ভ্যারিয়েবলের ধরণ" সর্বদা উপস্থিত থাকে এবং প্রকারের প্যারামিটার হিসাবে প্রায় পাশ করা যায়। উদাহরণ স্বরূপ:
val x = 5
def f[T](v: T) = v
f(x) // T is Int, the type of x
কিন্তু তার উপর নির্ভর করে আপনি কি করতে চান না , আপনি সাহায্য করবে না। উদাহরণস্বরূপ, ভেরিয়েবলের ধরণ কী তা জানতে না চাইতে পারেন, তবে মানটির ধরণটি কোনও নির্দিষ্ট ধরণের কিনা তা জানতে চাই :
val x: Any = 5
def f[T](v: T) = v match {
case _: Int => "Int"
case _: String => "String"
case _ => "Unknown"
}
f(x)
এখানে ভেরিয়েবলের ধরণ কী তা বিবেচনা করে না Any
। কী গুরুত্বপূর্ণ, যা যাচাই করা হয় তা হ'ল ধরণ 5
, মান। আসলে, T
অকেজো - আপনি পাশাপাশি এটি লিখতে পারে def f(v: Any)
। এছাড়াও, এটি ClassTag
একটি বা মানগুলির ব্যবহার করে Class
, যা নীচে ব্যাখ্যা করা হয়েছে, এবং কোনও ধরণের ধরণের পরামিতিগুলি পরীক্ষা করতে পারে না: আপনি কিছু একটি List[_]
( কোনও কিছুর List
) কিনা তা পরীক্ষা করে দেখতে পারেন, উদাহরণস্বরূপ, এটি একটিList[Int]
বা List[String]
।
আরেকটি সম্ভাবনা হ'ল আপনি ভেরিয়েবলের ধরণটি সংশোধন করতে চান । অর্থাৎ আপনি একটি মান টাইপ রূপান্তর করতে চান, তাই আপনি এটি সংরক্ষণ করতে পারেন, এটি প্রায় পাস ইত্যাদি এই প্রতিফলন জড়িত থাকে, এবং আপনি ব্যবহার হয় হবেন ClassTag
বা TypeTag
। উদাহরণ স্বরূপ:
val x: Any = 5
import scala.reflect.ClassTag
def f[T](v: T)(implicit ev: ClassTag[T]) = ev.toString
f(x) // returns the string "Any"
এ ClassTag
আপনাকে প্রাপ্ত প্যারামিটারগুলি টাইপ করতে দেয় match
। এটি কাজ করবে না:
def f[A, B](a: A, b: B) = a match {
case _: B => "A is a B"
case _ => "A is not a B"
}
তবে এটি করবে:
val x = 'c'
val y = 5
val z: Any = 5
import scala.reflect.ClassTag
def f[A, B: ClassTag](a: A, b: B) = a match {
case _: B => "A is a B"
case _ => "A is not a B"
}
f(x, y) // A (Char) is not a B (Int)
f(x, z) // A (Char) is a B (Any)
এখানে আমি ব্যবহার করছি প্রসঙ্গ সীমা সিনট্যাক্স, B : ClassTag
, যা শুধু পূর্ববর্তী মধ্যে অন্তর্নিহিত প্যারামিটার মত কাজ করে ClassTag
উদাহরণ, কিন্তু একটি বেনামী পরিবর্তনশীল ব্যবহার করে।
ClassTag
এর Class
মতো একটি মান থেকে একটিও পেতে পারে :
val x: Any = 5
val y = 5
import scala.reflect.ClassTag
def f(a: Any, b: Any) = {
val B = ClassTag(b.getClass)
ClassTag(a.getClass) match {
case B => "a is the same class as b"
case _ => "a is not the same class as b"
}
}
f(x, y) == f(y, x) // true, a is the same class as b
এ ClassTag
এটি সীমিত তবে এটি কেবল বেস শ্রেণিটি জুড়ে তবে এর ধরণের পরামিতিগুলি নয়। যে, ClassTag
জন্য List[Int]
এবং List[String]
একই List
,। আপনার যদি টাইপ পরামিতিগুলির প্রয়োজন হয় তবে TypeTag
তার পরিবর্তে আপনাকে অবশ্যই একটি ব্যবহার করতে হবে । এ TypeTag
তবে, কোনও মান থেকে পাওয়া যায় না, এবং এটি জেভিএম এর ক্ষয়ের কারণে কোনও প্যাটার্ন ম্যাচেও ব্যবহার করা যায় না ।
উদাহরণ সহ TypeTag
জটিল জটিল হতে পারে - এমনকি দুই ধরণের ট্যাগের তুলনা করাও একেবারে সহজ নয়, যা নীচে দেখা যায়:
import scala.reflect.runtime.universe.TypeTag
def f[A, B](a: A, b: B)(implicit evA: TypeTag[A], evB: TypeTag[B]) = evA == evB
type X = Int
val x: X = 5
val y = 5
f(x, y) // false, X is not the same type as Int
অবশ্যই, সেই তুলনাটি সত্য করে তোলার উপায় রয়েছে তবে সত্যিকার অর্থে এটির জন্য কয়েকটি বইয়ের অধ্যায় প্রয়োজন হবে TypeTag
, তাই আমি এখানেই থামব।
শেষ অবধি, আপনি ভেরিয়েবলের ধরণটি মোটেই পাত্তা দিচ্ছেন না। হতে পারে আপনি কেবল জানতে চান যে কোনও মানের শ্রেণি কী, এক্ষেত্রে উত্তরটি বরং সহজ:
val x = 5
x.getClass // int -- technically, an Int cannot be a class, but Scala fakes it
তবে আপনি কী সম্পাদন করতে চান সে সম্পর্কে আরও সুনির্দিষ্ট হওয়া ভাল, যাতে উত্তরটি আরও বেশি হতে পারে।
Int
হয় Any
, কিন্তু Any
হয় না Int
। এটি স্কেলা ২.১০ এ কাজ করে এবং এটি স্কেলা ২.১১ এ কাজ করা উচিত এবং কেন তা হয় তা আমি জানি না।
a match { case _: B => ...
ভেরিয়েবলের প্রকৃত মানের a
ধরণ নয়, ভেরিয়েবলের ধরণের নয় a
। আপনি ঠিক বলেছেন যে এটি স্কেলে ২.১০..6 এ যা বলে তা ফিরিয়ে দেয়। তবে এটি একটি বাগ হওয়া উচিত। স্কেল 2.11.8 এ প্রকৃত মানের ধরণের পরীক্ষা করা হয়, যেমনটি হওয়া উচিত।
আমি মনে করি প্রশ্নটি অসম্পূর্ণ। যদি আপনি বোঝাতে চেয়েছিলেন যে আপনি নীচে কিছু টাইপক্লাসের ধরণের তথ্য পেতে চান:
আপনি যদি নির্দিষ্ট করে মুদ্রণ করতে চান তবে:
scala> def manOf[T: Manifest](t: T): Manifest[T] = manifest[T]
manOf: [T](t: T)(implicit evidence$1: Manifest[T])Manifest[T]
scala> val x = List(1,2,3)
x: List[Int] = List(1, 2, 3)
scala> println(manOf(x))
scala.collection.immutable.List[Int]
আপনি যদি repl মোডে থাকেন তবে
scala> :type List(1,2,3)
List[Int]
বা আপনি যদি কেবল ক্লাসের ধরনটি জানতে চান তবে @ মোঙ্কজ্যাক ব্যাখ্যা হিসাবে "string".getClass
উদ্দেশ্যটি সমাধান করতে পারে
typeof x
, এখানে manOf(x)
তথ্য টাইপ বলুন!
যদি কোনও ভেরিয়েবলের প্রকারের দ্বারা আপনি অবজেক্টের রানটাইম ক্লাসটি বোঝাতে চান যা ভেরিয়েবলটি নির্দেশ করে, তবে আপনি এটি সমস্ত শ্রেণীর রেফারেন্সের মাধ্যমে পেতে পারেন objects
val name = "sam";
name: java.lang.String = sam
name.getClass
res0: java.lang.Class[_] = class java.lang.String
তবে আপনি যদি ভেরিয়েবল হিসাবে প্রকার হিসাবে ঘোষিত টাইপটি বোঝাতে চান তবে আপনি তা পেতে পারেন না। যেমন, আপনি যদি বলেন
val name: Object = "sam"
তারপরেও আপনি String
উপরের কোডটি থেকে ফিরে পাবেন ।
name.getClass.getSimpleName
আরও পঠনযোগ্য আউটপুটটির জন্যও করতে পারেন
আমি এটি পরীক্ষা করেছি এবং এটি কার্যকর হয়েছে
val x = 9
def printType[T](x:T) :Unit = {println(x.getClass.toString())}
5
উভয়ের উদাহরণInt
এবং একটি উদাহরণAny
। তা ছাড়া, আপনার ব্যাখ্যাটি নিখুঁত ছিল :)