Scala 了解类型构造函数扩展的类型构造函数的类型参数,找出类型构造函数的类型参数
设Scala 了解类型构造函数扩展的类型构造函数的类型参数,找出类型构造函数的类型参数,scala,scala-reflect,Scala,Scala Reflect,设X为类型构造函数,类型参数为A1,A2,…,An。例如选项[A]和功能1[A1、A2] 设X[T1,T2,…,Tn]为将类型构造函数X应用于具体类型参数T1,T2Tn。例如Option[Int]和Function1[Long,List[String]] 假设Y是X的一个直接子类,它保留X的一些类型参数不固定,不添加新的自由类型参数,其类型参数是B1,B2,…,Bm和m,这是部分答案。它只找出基类X的类型参数与直接子类Y的类型参数之间的关系 import scala.reflect.runtim
X
为类型构造函数,类型参数为A1
,A2
,…,An
。例如选项[A]
和功能1[A1、A2]
设X[T1,T2,…,Tn]
为将类型构造函数X
应用于具体类型参数T1
,T2
<代码>Tn。例如Option[Int]
和Function1[Long,List[String]]
假设
Y
是X
的一个直接子类,它保留X
的一些类型参数不固定,不添加新的自由类型参数,其类型参数是B1
,B2
,…,Bm
和m,这是部分答案。它只找出基类X
的类型参数与直接子类Y
的类型参数之间的关系
import scala.reflect.runtime.universe._
/** @param baseType a type resulting of the instantiation of a type constructor. For example: {{{typeOf[Option[Int]]}}}
* @param directSubclassTypeConstructor the type constructor whose type parameters we want to instantiate. It should be a subclass of the `baseType`'s type constructor.
* @return the relationship between `baseType`'s type arguments and `directSubclassTypeconstructor`'s type parameters. For example: {{{Map(A -> Int)}}}*/
def typeParametersToBaseTypeArgumentsRelationship(baseType: Type, directSubclassTypeConstructor: Type): Map[Type, Type] = {
val baseTypeConstructor = baseType.typeConstructor;
assert(directSubclassTypeConstructor <:< baseTypeConstructor)
val typeParamsRelationship =
for {
(baseTypeParam, baseTypeArgument) <- baseTypeConstructor.typeParams zip baseType.typeArgs
} yield {
val directSubclassTypeParam = baseTypeParam.asType.toType.asSeenFrom(directSubclassTypeConstructor, baseType.typeSymbol)
directSubclassTypeParam -> baseTypeArgument
}
typeParamsRelationship.toMap
}
另一个更有趣的用法示例:
scala> import scala.reflect.runtime.universe._
scala> typeParametersToBaseTypeArgumentsRelationship(
typeOf[Function1[Long, List[String]]],
typeOf[PartialFunction[_, _]].typeConstructor
)
val res1: Map[reflect.runtime.universe.Type, reflect.runtime.universe.Type] =
Map(A -> Long, B -> List[String])
sealed trait X[A1, A2, A3]
class Y[B1, B2] extends X[B2, List[B1], B1] {}
scala> typeParametersToBaseTypeArgumentsRelationship(
typeOf[X[Long, List[String], String]],
typeOf[Y[_, _]].typeConstructor
)
val res2: Map[reflect.runtime.universe.Type,reflect.runtime.universe.Type] =
Map(B2 -> Long, List[B1] -> List[String], B1 -> String)
scala> applySubclassTypeConstructor(
typeOf[Option[Int]],
typeOf[Some[_]].typeConstructor
)
val res1: reflect.runtime.universe.Type =
Some[Int]
sealed trait X[A1, A2, A3]
class Y[B1, B2] extends X[B2, List[B1], B1] {}
scala> applySubclassTypeConstructor(
typeOf[X[Long, List[String], String]],
typeOf[Y[_, _]].typeConstructor
)
val res2: reflect.runtime.universe.Type =
Y[String,Long]
回答这个问题缺少的部分是创建一个带有根据给定关系实例化的类型参数的directSubclassTypeConstructor
副本。这需要我所没有的知识
编辑:
在了解了如何将类型参数应用于类型构造函数之后,我能够完成这个答案
import scala.reflect.runtime.universe._
/** Given a type `baseType` and a type constructor of one of its direct subclasses `directSubclassTypeConstructor`, creates a type by applying said type constructor to the type arguments that were used to create the `baseType` as seen from said direct subclass.
* @param baseType a type resulting of the instantiation of a type constructor. For example: {{{typeOf[Option[Int]]}}}
* @param directSubclassTypeConstructor the type constructor we want to instantiate such that it is assignable to `baseType`. For example: {{{typeOf[Some[_]].typeConstructor}}}
* @return the type constructed by applying the type constructor `directSubclassTypeConstructor` to the type arguments of `baseType` as seen from said type constructor. For example: {{{typeOf[Some[Int]]}}}*/
def applySubclassTypeConstructor(baseType: Type, directSubclassTypeConstructor: Type): Type = {
val directSubclassTypeParams = directSubclassTypeConstructor.typeParams
if( directSubclassTypeParams.isEmpty) {
directSubclassTypeConstructor
} else {
val baseTypeConstructor = baseType.typeConstructor;
assert(directSubclassTypeConstructor <:< baseTypeConstructor)
val subclassTypeParamsToBaseTypeArgumentsRelationship=
for {
(baseTypeParam, baseTypeArgument) <- baseTypeConstructor.typeParams zip baseType.typeArgs
} yield {
val directSubclassTypeParam = baseTypeParam.asType.toType.asSeenFrom(directSubclassTypeConstructor, baseType.typeSymbol)
directSubclassTypeParam -> baseTypeArgument
}
val directSubclassTypeArguments =
for (subclassTypeParm <- directSubclassTypeParams) yield {
subclassTypeParamsToBaseTypeArgumentsRelationship.find { r =>
r._1.typeSymbol.name == subclassTypeParm.name
}.get._2
}
appliedType(directSubclassTypeConstructor, directSubclassTypeArguments)
}
}
intrincate使用示例:
scala> import scala.reflect.runtime.universe._
scala> typeParametersToBaseTypeArgumentsRelationship(
typeOf[Function1[Long, List[String]]],
typeOf[PartialFunction[_, _]].typeConstructor
)
val res1: Map[reflect.runtime.universe.Type, reflect.runtime.universe.Type] =
Map(A -> Long, B -> List[String])
sealed trait X[A1, A2, A3]
class Y[B1, B2] extends X[B2, List[B1], B1] {}
scala> typeParametersToBaseTypeArgumentsRelationship(
typeOf[X[Long, List[String], String]],
typeOf[Y[_, _]].typeConstructor
)
val res2: Map[reflect.runtime.universe.Type,reflect.runtime.universe.Type] =
Map(B2 -> Long, List[B1] -> List[String], B1 -> String)
scala> applySubclassTypeConstructor(
typeOf[Option[Int]],
typeOf[Some[_]].typeConstructor
)
val res1: reflect.runtime.universe.Type =
Some[Int]
sealed trait X[A1, A2, A3]
class Y[B1, B2] extends X[B2, List[B1], B1] {}
scala> applySubclassTypeConstructor(
typeOf[X[Long, List[String], String]],
typeOf[Y[_, _]].typeConstructor
)
val res2: reflect.runtime.universe.Type =
Y[String,Long]
很明显,对于某些[R1]@SimY4,R1=T1我所说的是正确的,因为我澄清了“去掉了差异”。它认为这是可以解决的。如果我是对的,编译器需要为类型推断解决它,还有“@SimY4请查看方法def asSeenFrom(pre:type,clazz:Symbol)的文档:Type
定义于scala.reflect.api.Types
。显然它解决了这个问题。但我不知道如何使用它。文档中的示例已过时,因为它使用了从api中删除的ThisType
。旁注:我确信有更好的方法来表达“可分配且已删除差异”“,因为我缺少术语。如果我将其替换为“对应于”。@Readren使用internal.thisType(C)
而不是thisType(C)
,问题可能会更清楚。