আমি রানটাইমে একটি ভেরিয়েবলের ধরণ পেতে চাই


99

আমি রানটাইমে একটি ভেরিয়েবলের ধরণ পেতে চাই। আমি এটা কিভাবে করবো?

উত্তর:


133

সুতরাং, কঠোরভাবে বলতে গেলে, "ভ্যারিয়েবলের ধরণ" সর্বদা উপস্থিত থাকে এবং প্রকারের প্যারামিটার হিসাবে প্রায় পাশ করা যায়। উদাহরণ স্বরূপ:

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

তবে আপনি কী সম্পাদন করতে চান সে সম্পর্কে আরও সুনির্দিষ্ট হওয়া ভাল, যাতে উত্তরটি আরও বেশি হতে পারে।


"তবে এটি হবে:" এর পরে আপনি যে উদাহরণ কোড লিখেছেন তা বিভ্রান্তিকর। এটি সংকলন করে তবে ফলাফলটি আপনি মন্তব্যে দেখান না। উভয় কল একই ফলাফল দেয়: "এ বি একটি বি"। কারণ মান 5উভয়ের উদাহরণ Intএবং একটি উদাহরণ Any। তা ছাড়া, আপনার ব্যাখ্যাটি নিখুঁত ছিল :)
রেডরেন

@ রেডরেন মানটি পরীক্ষিত হয় নি, শ্রেণিটি। Intহয় Any, কিন্তু Anyহয় না Int। এটি স্কেলা ২.১০ এ কাজ করে এবং এটি স্কেলা ২.১১ এ কাজ করা উচিত এবং কেন তা হয় তা আমি জানি না।
ড্যানিয়েল সি সোব্রাল

4
এটি আপনার মতো একটি বিশিষ্টতার বিরোধিতা করতে আমাকে ভয় দেখায়, তবে কোডটি a match { case _: B => ...ভেরিয়েবলের প্রকৃত মানের aধরণ নয়, ভেরিয়েবলের ধরণের নয় a। আপনি ঠিক বলেছেন যে এটি স্কেলে ২.১০..6 এ যা বলে তা ফিরিয়ে দেয়। তবে এটি একটি বাগ হওয়া উচিত। স্কেল 2.11.8 এ প্রকৃত মানের ধরণের পরীক্ষা করা হয়, যেমনটি হওয়া উচিত।
রেডরেন

ক্লাসট্যাগ এবং টাইপট্যাগের মধ্যে পার্থক্য সম্পর্কে খুব সুন্দর কভারেজ, আমি যা খুঁজছিলাম।
marcin_koss

এটি চেক করার কোনও উপায় আছে কি?
চিমনো

53

আমি মনে করি প্রশ্নটি অসম্পূর্ণ। যদি আপনি বোঝাতে চেয়েছিলেন যে আপনি নীচে কিছু টাইপক্লাসের ধরণের তথ্য পেতে চান:

আপনি যদি নির্দিষ্ট করে মুদ্রণ করতে চান তবে:

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উদ্দেশ্যটি সমাধান করতে পারে


4
পাঠকদের জন্য: এটি সবচেয়ে কার্যকর সমাধান । জাভাস্ক্রিপ্ট হিসাবে typeof x, এখানে manOf(x)তথ্য টাইপ বলুন!
পিটার ক্রাউস

23

যদি কোনও ভেরিয়েবলের প্রকারের দ্বারা আপনি অবজেক্টের রানটাইম ক্লাসটি বোঝাতে চান যা ভেরিয়েবলটি নির্দেশ করে, তবে আপনি এটি সমস্ত শ্রেণীর রেফারেন্সের মাধ্যমে পেতে পারেন objects

val name = "sam";
name: java.lang.String = sam
name.getClass
res0: java.lang.Class[_] = class java.lang.String

তবে আপনি যদি ভেরিয়েবল হিসাবে প্রকার হিসাবে ঘোষিত টাইপটি বোঝাতে চান তবে আপনি তা পেতে পারেন না। যেমন, আপনি যদি বলেন

val name: Object = "sam"

তারপরেও আপনি Stringউপরের কোডটি থেকে ফিরে পাবেন ।


8
আপনি name.getClass.getSimpleNameআরও পঠনযোগ্য আউটপুটটির জন্যও করতে পারেন
ডেভিড আরেনবুর্গ

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