Scala 绑定类型参数和反射
Scala bound type parameter and reflection
可以使用下面的Java代码:
public <T extends Enum<T>> T foo(Class<T> clazz) {
return clazz.getEnumConstants()[0];
}
public void bar(Class<?> clazz) {
if (Enum.class.isAssignableFrom(clazz)) {
System.out.println(foo(clazz.asSubclass(Enum.class)));
} else if (String.class.isAssignableFrom(clazz)) {
System.out.println("Meow");
}
}
bar(MyEnum.class) // prints the first value of MyEnum
bar(String.class) // prints Meow
被翻译成 Scala:
bar[MyEnum]()
bar[String]()
Enum
只是 class 遵循 T extends Wrapper[T]
模式的一个示例,而 foo
可以简单地返回 class 的名称(或执行任何其他类型的逻辑,需要仅在我的“Wrapper
”class 中可用的反射数据)。
我试图用 TypeTag
让它在 Scala 中工作但失败了;我遇到了各种编译错误,例如:inferred type arguments [?0] do not conform to method foo's type parameter bounds [E <: Enum[E]]
您可以尝试使用类型类方法,以便在编译时解决所有问题,不涉及反射:
import scala.reflect.ClassTag
trait DoSomething[T] {
def apply(): Unit
}
object DoSomething {
implicit def enumDoSomething[E <: Enum[E]](implicit ct: ClassTag[E]) = new DoSomething[E] {
def apply() = println(ct.runtimeClass.getEnumConstants()(0))
}
implicit object stringDoSomething extends DoSomething[String] {
def apply() = println("Meow")
}
}
object Test extends App {
def foo[A](implicit doSomething: DoSomething[A]) = doSomething()
foo[java.util.concurrent.TimeUnit]
foo[String]
}
这样你就没有 if-else 并且你有更好的关注点分离。
如果你想要一个 "default" 案例,你可以有一个包罗万象的隐式。
import scala.reflect.ClassTag
trait DoSomething[T] {
def apply(): Unit
}
object DoSomething {
implicit def enumDoSomething[E <: Enum[E]](implicit ct: ClassTag[E]) = new DoSomething[E] {
def apply() = println(ct.runtimeClass.getEnumConstants()(0))
}
implicit object stringDoSomething extends DoSomething[String] {
def apply() = println("Meow")
}
implicit def catchAll[T] = new DoSomething[T] {
def apply() = {
println("test") // some default case
}
}
}
object Test extends App {
def foo[A](implicit doSomething: DoSomething[A]) = doSomething()
foo[java.util.concurrent.TimeUnit] // prints NANOSECONDS
foo[String] // prints Meow
foo[Long] // prints test
}
如果您对 scala 如何查找隐式感兴趣,take a look at this
很可能有更好的方法来完成您实际需要的事情,但是:
import language.existentials
import reflect.ClassTag
def foo[T <: Enum[T]](implicit ct: ClassTag[T]) = ct
def bar[T](implicit ct: ClassTag[T]) = {
val clazz = ct.runtimeClass
if (classOf[Enum[_]].isAssignableFrom(clazz)) {
println(foo(ct.asInstanceOf[ClassTag[A] forSome { type A <: Enum[A] }]))
} else {
println("not a enum")
}
}
可以使用下面的Java代码:
public <T extends Enum<T>> T foo(Class<T> clazz) {
return clazz.getEnumConstants()[0];
}
public void bar(Class<?> clazz) {
if (Enum.class.isAssignableFrom(clazz)) {
System.out.println(foo(clazz.asSubclass(Enum.class)));
} else if (String.class.isAssignableFrom(clazz)) {
System.out.println("Meow");
}
}
bar(MyEnum.class) // prints the first value of MyEnum
bar(String.class) // prints Meow
被翻译成 Scala:
bar[MyEnum]()
bar[String]()
Enum
只是 class 遵循 T extends Wrapper[T]
模式的一个示例,而 foo
可以简单地返回 class 的名称(或执行任何其他类型的逻辑,需要仅在我的“Wrapper
”class 中可用的反射数据)。
我试图用 TypeTag
让它在 Scala 中工作但失败了;我遇到了各种编译错误,例如:inferred type arguments [?0] do not conform to method foo's type parameter bounds [E <: Enum[E]]
您可以尝试使用类型类方法,以便在编译时解决所有问题,不涉及反射:
import scala.reflect.ClassTag
trait DoSomething[T] {
def apply(): Unit
}
object DoSomething {
implicit def enumDoSomething[E <: Enum[E]](implicit ct: ClassTag[E]) = new DoSomething[E] {
def apply() = println(ct.runtimeClass.getEnumConstants()(0))
}
implicit object stringDoSomething extends DoSomething[String] {
def apply() = println("Meow")
}
}
object Test extends App {
def foo[A](implicit doSomething: DoSomething[A]) = doSomething()
foo[java.util.concurrent.TimeUnit]
foo[String]
}
这样你就没有 if-else 并且你有更好的关注点分离。
如果你想要一个 "default" 案例,你可以有一个包罗万象的隐式。
import scala.reflect.ClassTag
trait DoSomething[T] {
def apply(): Unit
}
object DoSomething {
implicit def enumDoSomething[E <: Enum[E]](implicit ct: ClassTag[E]) = new DoSomething[E] {
def apply() = println(ct.runtimeClass.getEnumConstants()(0))
}
implicit object stringDoSomething extends DoSomething[String] {
def apply() = println("Meow")
}
implicit def catchAll[T] = new DoSomething[T] {
def apply() = {
println("test") // some default case
}
}
}
object Test extends App {
def foo[A](implicit doSomething: DoSomething[A]) = doSomething()
foo[java.util.concurrent.TimeUnit] // prints NANOSECONDS
foo[String] // prints Meow
foo[Long] // prints test
}
如果您对 scala 如何查找隐式感兴趣,take a look at this
很可能有更好的方法来完成您实际需要的事情,但是:
import language.existentials
import reflect.ClassTag
def foo[T <: Enum[T]](implicit ct: ClassTag[T]) = ct
def bar[T](implicit ct: ClassTag[T]) = {
val clazz = ct.runtimeClass
if (classOf[Enum[_]].isAssignableFrom(clazz)) {
println(foo(ct.asInstanceOf[ClassTag[A] forSome { type A <: Enum[A] }]))
} else {
println("not a enum")
}
}