是否有可能(通过宏,某种形式的无形自动或其他形式)获得密封特征的子类列表:
给出一个简单的参数化类型class LK[A]
,我可以写
// or simpler def tagLK[A: TypeTag] = typeTag[LK[A]]
def tagLK[A](implicit tA: TypeTag[A]) = typeTag[LK[A]]
tagLK[Int] == typeTag[LK[Int]] // true
Run Code Online (Sandbox Code Playgroud)
现在我想写一个类似的class HK[F[_], A]
:
def tagHK[F[_], A](implicit ???) = typeTag[HK[F, A]]
// or some other implementation?
tagHK[Option, Int] == typeTag[HK[Option, Int]]
Run Code Online (Sandbox Code Playgroud)
这可能吗?我试过了
def tagHK[F[_], A](implicit tF: TypeTag[F[_]], tA: TypeTag[A]) = typeTag[HK[F, A]]
def tagHK[F[_], A](implicit tF: TypeTag[F], tA: TypeTag[A]) = typeTag[HK[F, A]]
Run Code Online (Sandbox Code Playgroud)
但是由于显而易见的原因(在第一种情况下F[_]
是存在类型而不是更高级的类型,在第二种TypeTag[F]
情况下不能编译),它们都不起作用.
我怀疑答案是"这是不可能的",但如果不是,那将非常高兴.
编辑:我们目前使用WeakTypeTag
如下(略微简化):
trait Element[A] {
val tag: …
Run Code Online (Sandbox Code Playgroud) 以下代码成功,但是有更好的方法做同样的事情吗?也许是案例类特有的东西?在下面的代码中,对于我的简单案例类中String类型的每个字段,代码遍历我的案例类的实例列表,并查找该字段的最长字符串的长度.
case class CrmContractorRow(
id: Long,
bankCharges: String,
overTime: String,
name$id: Long,
mgmtFee: String,
contractDetails$id: Long,
email: String,
copyOfVisa: String)
object Go {
def main(args: Array[String]) {
val a = CrmContractorRow(1,"1","1",4444,"1",1,"1","1")
val b = CrmContractorRow(22,"22","22",22,"55555",22,"nine long","22")
val c = CrmContractorRow(333,"333","333",333,"333",333,"333","333")
val rows = List(a,b,c)
c.getClass.getDeclaredFields.filter(p => p.getType == classOf[String]).foreach{f =>
f.setAccessible(true)
println(f.getName + ": " + rows.map(row => f.get(row).asInstanceOf[String]).maxBy(_.length))
}
}
}
Run Code Online (Sandbox Code Playgroud)
结果:
bankCharges: 3
overTime: 3
mgmtFee: 5
email: 9
copyOfVisa: 3
Run Code Online (Sandbox Code Playgroud) 假设我有一个Generic超类:
class GenericExample[T](
a: String,
b: T
) {
def fn(i: T): T = b
}
Run Code Online (Sandbox Code Playgroud)
和一个具体的子类:
case class Example(
a: String,
b: Int
) extends GenericExample[Int](a, b)
Run Code Online (Sandbox Code Playgroud)
我想通过scala反射得到函数"fn"的类型参数,所以我选择并过滤其成员:
import ScalaReflection.universe._
val baseType = typeTag[Example]
val member = baseType
.tpe
.member(methodName: TermName)
.asTerm
.alternatives
.map(_.asMethod)
.head
val paramss = member.paramss
val actualTypess: List[List[Type]] = paramss.map {
params =>
params.map {
param =>
param.typeSignature
}
}
Run Code Online (Sandbox Code Playgroud)
我期待scala给我正确的结果List(List(Int))
,相反,我只得到了通用List(List(T))
通过文档进行处理我发现typeSignature是罪魁祸首:
* This method always returns signatures in the most generic …
Run Code Online (Sandbox Code Playgroud) 简介:
...
TypeTag[T]
封装某些编译时类型的运行时类型表示T
....
...TypeTag
s的总是由编译器生成....... [1]
TypeTag
s位于scala.reflect.**
包装中.另一个SO回答提到使用java反射会在应用程序中产生运行时性能开销.
问题:s,s和s在运行时使用java反射的
程度如何?它们是在编译时生成的,但它们在使用时是否会导致运行时性能开销?TypeTag
ClassTag
WeakTypeTag
示例:
def isOfType[A : ClassTag : TypeTag, E : ClassTag : TypeTag](actual: A, expected: E): Boolean = {
actual match {
case _ : E if typeOf[A] =:= typeOf[E] => true
case _ => false
}
}
assert( isOfType(List.empty[Int], List.empty[Int]))
assert(!isOfType(List.empty[String], List.empty[Int]))
Run Code Online (Sandbox Code Playgroud)
虽然标签是在编译时生成的,但我可以在运行时感受到延迟.类型比较是否使用了引擎盖下不那么高效的java反射?
我有一个表面上很简单的宏观问题,我已经用头撞了几个小时,但没有运气。也许有更多经验的人可以提供帮助。
我有以下宏:
import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
object MacroObject {
def run(s: String): Unit =
macro runImpl
def runImpl(c: Context)(s: c.Tree): c.Tree = {
import c.universe._
println(s) // <-- I need the macro to know the value of s at compile time
q"()"
}
}
Run Code Online (Sandbox Code Playgroud)
问题是:我希望宏知道s
传递给它的值——不是 AST s
,而是s
它本身的值。具体来说,我希望它具有这种行为:
def runTheMacro(str: String): Unit = MacroObject.run(str)
final val HardCodedString1 = "Hello, world!"
runTheMacro(HardCodedString1) // the macro should print "Hello, world!"
// to the console during macro expansion …
Run Code Online (Sandbox Code Playgroud) 在 Scala 反射中,通常可以使用 TypeCreator 从 Type 构造 TypeTag:
object TypeUtils {
import ScalaReflection.universe._
def createTypeTag[T](
tpe: Type,
mirror: reflect.api.Mirror[reflect.runtime.universe.type]
): TypeTag[T] = {
TypeTag.apply(
mirror,
NaiveTypeCreator(tpe)
)
}
case class NaiveTypeCreator(tpe: Type) extends reflect.api.TypeCreator {
def apply[U <: reflect.api.Universe with Singleton](
m: reflect.api.Mirror[U]): U#Type = {
// assert(m eq mirror, s"TypeTag[$tpe] defined in $mirror cannot be migrated to $m.")
tpe.asInstanceOf[U#Type]
}
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,事实证明 的输出createTypeTag
不可序列化,这与编译时推理创建的 typeTag 不同:
import java.io.{ByteArrayOutputStream, ObjectOutputStream}
import org.apache.spark.sql.catalyst.ScalaReflection
import org.scalatest.FunSpec
class TypeTagFromType extends FunSpec { …
Run Code Online (Sandbox Code Playgroud) 现在scala已经使用类型类迭代了JVM 类型的擦除修复ClassTag
,为什么它是一个选择加入,而不是让编译器总是捕获运行时检查的类型签名.使它具有隐式参数化类型约束将使得classTag[T]
无论泛型参数声明如何都可以调用.
编辑:我应该澄清,我并不是说scala应该改变幕后的签名,总是包含在内ClassTag
.相反,我的意思是,因为ClassTag
显示scala可以捕获运行时类型信息并因此避免类型擦除限制,为什么不能将该捕获隐含为编译器的一部分,以便该信息始终在scala代码中可用?
我怀疑它是向后兼容性,java生态系统兼容性,二进制大小或运行时开销相关,但这些只是猜测.
我试图在编译时列出包中的所有类。
让我们定义一个具有以下结构的项目:
com.main
Main.scala
com.package
Method.scala
com.package.method1
Method1.scala
com.package.method2
Method2.scala
Run Code Online (Sandbox Code Playgroud)
在哪里:
方法.scala
abstract class Method(val name: String) {
}
Run Code Online (Sandbox Code Playgroud)
Method1.scala 和 Method2.scala (更改各自的名称)
class Method1 extends Method(name = "Method1") {
}
Run Code Online (Sandbox Code Playgroud)
我想从 Main.scala 获取 com.package._ 中定义的类列表,如下所示:
object Main() {
val names = List("Method1", "Method2")
}
Run Code Online (Sandbox Code Playgroud)
我可以对名称进行硬编码(如图所示),但我想知道是否可以在编译时获取这些名称。我知道在运行时可以使用http://software.clapper.org/classutil/
我知道我可以使用工具箱在 Scala 中编译单个“片段”,如下所示:
import scala.reflect.runtime.universe
import scala.tools.reflect.ToolBox
object Compiler {
val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
def main(args: Array[String]): Unit = {
tb.eval(tb.parse("""println("hello!")"""))
}
}
Run Code Online (Sandbox Code Playgroud)
有什么方法可以编译不仅仅是“片段”,即相互引用的类?像这样:
import scala.reflect.runtime.universe
import scala.tools.reflect.ToolBox
object Compiler {
private val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
val a: String =
"""
|package pkg {
|
|class A {
|def compute(): Int = 42
|}}
""".stripMargin
val b: String =
"""
|import pkg._
|
|class B {
|def fun(): Unit = {
| new A().compute()
|}
|}
""".stripMargin
def main(args: Array[String]): …
Run Code Online (Sandbox Code Playgroud) scala ×10
scala-reflect ×10
reflection ×4
scala-macros ×3
shapeless ×2
case-class ×1
generics ×1
java ×1
jvm ×1
macros ×1
runtime ×1
type-erasure ×1
typeclass ×1
types ×1