[英]How to pass Type at Runtime to Polymorphic function scala
Below is a sample example. 下面是一个示例示例。 Where i need to convert value stored in String as a Type and pass that to polymorphic function in scala. 我需要将存储在String中的值转换为Type并将其传递给scala中的多态函数。
import scala.reflect.runtime.universe._
import scala.reflect.api
object Test {
def convert[T](l: String)(implicit typeTag: TypeTag[T]): T = l.asInstanceOf[T]
implicit def stringToTypeTag[A](name: String): TypeTag[A] = {
val c = Class.forName(name)
val mirror = runtimeMirror(c.getClassLoader)
val sym = mirror.staticClass(name)
val tpe = sym.selfType
TypeTag(mirror, new api.TypeCreator {
def apply[U <: api.Universe with Singleton](m: api.Mirror[U]) =
if (m eq mirror) tpe.asInstanceOf[U # Type]
else throw new IllegalArgumentException(s"Type tag defined in $mirror cannot be migrated to other mirrors.")
})
}
def main(args:Array[String]): Unit = {
val typ = "Integer"
val x = convert("10")(stringToTypeTag("java.lang." + typ))
val y = convert("20")(stringToTypeTag("java.lang." + typ))
println(x.getClass)
println(y.getClass)
val z = x + y
println(z)
// Expected OP 30
val typ = "String"
val x1 = convert("10")(stringToTypeTag("java.lang." + typ))
val y1 = convert("20")(stringToTypeTag("java.lang." + typ))
println(x1.getClass)
println(y1.getClass)
val z1 = x1 + y1
println(z1)
// Expected OP 1020
}
}
Expected OP: 30 when Integer and 1020 when String 预期的OP:整数时为30,字符串时为1020
There are too many problems in this code, I am stating just the most obvious one as the deeper problems require a blog and not an answer. 这段代码中有太多问题,我只想指出最明显的一个,因为更深层次的问题需要博客而不是答案。
So, this method, 所以这个方法
def convert[T](l: String)(implicit typeTag: TypeTag[T]): T = l.asInstanceOf[T]
The most obvious problem here is trying to convert a String
to T
by using l.asInstanceOf[T]
. 这里最明显的问题是尝试使用l.asInstanceOf[T]
将String
转换为T
This is not how things work, you can not just convert a String
to a T
by doing asInstanceOf
. 这不是工作原理,您不能仅通过asInstanceOf
将String
转换为T
Let me show when is this asInstanceOf
can be used. 让我说明何时可以使用此asInstanceOf
。
// Lets say, there was an Int
scala> val i: Int = 10
// i: Int = 10
// but it was somehow assigned to a variable of type Any
scala> val a: Any = i
// a: Any = 10
// Now, even if we know that the value is an Int
// but since the variable is Any, we can not do Int like things on it
scala> a / 2
// <console>:13: error: value / is not a member of Any .
// a / 2
// ^
// you can use `asInstanceOf` again access it as an Int
scala> a.asInstanceOf[Int] / 2
// res4: Int = 5
But only because the value
was already an Int
, just the variable
was of type Any
. 但是仅由于该value
已经是一个Int
,所以该variable
的类型才是Any
。
What you are trying to do, it to cast a value
of type String
to some T
. 您要尝试执行的操作是将String
类型的value
String
为T
Other than this you are mixing a lot of compile time things with run time things, which will not work out for a lot of reasons. 除此之外,您还会将许多编译时事物与运行时事物混合在一起,由于许多原因,它们将无法解决。
You should look into a config library such as lightbend-config or pureconfig. 您应该查看配置库,例如lightbend-config或pureconfig。 Or a reader implementation such as following. 或阅读器的实现,例如以下。
trait ConfigReader[A] {
def read(input: String): A
}
object ConfigReader {
object Implicits {
implicit val intConfigReader = new ConfigReader[Int] {
override def read(input: String): Int = input.toInt
}
implicit val doubleConfigReader = new ConfigReader[Double] {
override def read(input: String): Double = input.toDouble
}
implicit val stringConfigReader = new ConfigReader[String] {
override def read(input: String): String = input
}
}
def read[A](input: String)(implicit configReader: ConfigReader[A]) = configReader.read(input)
}
import ConfigReader.Implicits._
val i = ConfigReader.read[Int]("5")
val d = ConfigReader.read[Double]("5.0")
This is not going to work because function polymorphism is done at compile time, not run time. 这是行不通的,因为函数多态性是在编译时而不是运行时完成的。 So you can't select a polymorphic function based on the name of a type that is read from a file. 因此,您不能基于从文件读取的类型的名称来选择多态函数。
The underlying problem is that the type of a variable is determined at compile time. 潜在的问题是变量的类型是在编译时确定的。 So the compiler has to pick the type of x
and y
before the type is read from the configuration. 因此,编译器必须先选择x
和y
的类型,然后才能从配置中读取类型。 Since x
and y
could one of a number of types, the compiler probably chooses Any
. 由于x
和y
可以是多种类型之一,因此编译器可能选择Any
。
This is theoretically OK so far because an Any
variable can hold either Int
or String
. 到目前为止,这在理论上是可以的,因为Any
变量可以容纳Int
或String
。 But things go wrong when you try to add them: x + y
. 但是,当您尝试添加它们时,事情就出错了: x + y
。 This is telling the compiler to add an Any
to an Any
and this is clearly going to go badly. 这是告诉编译器在Any
上添加Any
,这显然很不好。 The program does not use the run-time type of x
and y
to pick the appropriate +
function. 该程序不使用x
和y
的运行时类型来选择适当的+
函数。
Considering the new requirement details given in the comments, you can do something like following. 考虑到注释中给出的新需求详细信息,您可以执行以下操作。
import scala.reflect.ClassTag
import scala.util.{Try, Success, Failure}
case class Repr[+A: ClassTag](value: A)
def readInputAsRepr(
input: String,
valueType: String
): Try[Repr[Any]] =
valueType match {
case "Int" => Try(Repr[Integer](input.toInt))
case "Double" => Try(Repr[Double](input.toDouble))
case "String" => Try(Repr[String](input))
case _ => Failure(new UnsupportedOperationException)
}
def intSumAction(i1: Int, i2: Int) = i1 + i2
def doubleSumAction(d1: Double, d2: Double) = d1 + d2
def stringSumAction(s1: String, s2: String) = s1 + s2
def selectAndEvaluateAction(
repr1: Repr[Any],
repr2: Repr[Any]
): Try[Repr[Any]] =
(repr1.value, repr2.value) match {
case (a1: Int, a2: Int) => Success(Repr(intSumAction(a1, a2)))
case (a1: Double, a2: Double) => Success(Repr(doubleSumAction(a1, a2)))
case (a1: String, a2: String) => Success(Repr(stringSumAction(a1, a2)))
case _ => Failure(new UnsupportedOperationException)
}
val x1 = readInputAsRepr("10", "Int").get
val y1 = readInputAsRepr("20", "Int").get
val z1 = selectAndEvaluateAction(x1, y1)
val x2 = readInputAsRepr("10", "String").get
val y2 = readInputAsRepr("20", "String").get
val z2 = selectAndEvaluateAction(x2, y2)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.