找出类型构造函数的类型参数,知道它扩展的类型构造函数的类型参数
Find out the type arguments for a type constructor knowing the type arguments of the type constructor it extends
设 X
为具有类型参数 A1
、A2
、...、An
的类型构造函数。例如 Option[A]
和 Function1[A1, A2]
.
设 X[T1, T2, ..., Tn]
是将类型构造函数 X
应用于具体类型参数 T1
、T2
、... Tn
的类型结果.例如 Option[Int]
和 Function1[Long, List[String]]
.
设Y
为X
的直接子类,不固定X
的部分类型参数,不增加新的自由类型参数,其类型参数为B1
、B2
、...、Bm
和 m <= n
。例如 Some[B]
和 PartialFunction[B1, B2]
.
我需要实现一个函数来找出要分配给类型参数 R1
、R2
、...、Rm
的具体类型 B1
, B2
, ..., Bm
类型构造函数 Y
使得 Y[R1, R2, ..., Rm] <:< X[T1, T2, ..., Tn]
移除所有差异(所有特征和 类 被视为非变体) .
在 Option
和 Some
的情况下,很明显 R1 = T1
对于 Some[R1] <:< Option[T1]
移除方差是正确的。
此外,在 Function1
和 PartialFunction
的情况下,显然 R1 = T1
和 R2 = T2
对于 PartialFunction[R1, R2] <:< Function[T1, T2]
移除方差是正确的。
但是对于一般情况来说稍微复杂一些。
鉴于编译器和反射库的 <:<
运算符都必须解决此问题以检查可分配性;我假设反射函数 API 已经解决了我的问题。但我没有找到它。
Y假设它是def asSeenFrom(pre: Type, clazz: Symbol): Type
,但我试过了没有用。当然,我做错了什么。
这是回答这个问题的函数的用法示例:
import scala.reflect.runtime.universe._
val optionOfInt: Type = typeOf[Option[Int]]
val someTypeConstructor: ClassSymbol = typeOf[Some[_]].typeSymbol.asClass
val someOfInt: Type = instantiateSubclassTypeConstructor(optionOfInt, someTypeConstructor)
print(someOfInt.typeArgs) // outputs "List(Int)"
其中 instantiateSubclassTypeConstructor
是回答这个问题的函数。
/** @param baseInstantiation a class constructor instantiation. For example: {{{typeOf[Option[Int]]}}}
* @param directSubclassSymbol the [[ClassSymbol] of the class constructor we want to instantiate such that it is assignable to `baseInstantiantion`. For example: {{{typeOf[Some[_]].typeSymbol.asClass}}}
* @return a type instantiation of the class constructor referenced by the `directSubclassSymbol` such that it is assignable to `baseInstantiantion`. For example: {{{typeOf[Some[Int]]}}}
*/
def instantiateSubclassTypeConstructor(baseInstantiation: Type, directSubclassSymbol: ClassSymbol): Type = ???
scala 版本:2.13.3
这是部分答案。它只是找出基classX
的类型参数和直接子classY
.
的类型参数之间的关系
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)
回答问题的缺失部分是创建 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)
}
}
一个简单的用法示例:
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]
设 X
为具有类型参数 A1
、A2
、...、An
的类型构造函数。例如 Option[A]
和 Function1[A1, A2]
.
设 X[T1, T2, ..., Tn]
是将类型构造函数 X
应用于具体类型参数 T1
、T2
、... Tn
的类型结果.例如 Option[Int]
和 Function1[Long, List[String]]
.
设Y
为X
的直接子类,不固定X
的部分类型参数,不增加新的自由类型参数,其类型参数为B1
、B2
、...、Bm
和 m <= n
。例如 Some[B]
和 PartialFunction[B1, B2]
.
我需要实现一个函数来找出要分配给类型参数 R1
、R2
、...、Rm
的具体类型 B1
, B2
, ..., Bm
类型构造函数 Y
使得 Y[R1, R2, ..., Rm] <:< X[T1, T2, ..., Tn]
移除所有差异(所有特征和 类 被视为非变体) .
在 Option
和 Some
的情况下,很明显 R1 = T1
对于 Some[R1] <:< Option[T1]
移除方差是正确的。
此外,在 Function1
和 PartialFunction
的情况下,显然 R1 = T1
和 R2 = T2
对于 PartialFunction[R1, R2] <:< Function[T1, T2]
移除方差是正确的。
但是对于一般情况来说稍微复杂一些。
鉴于编译器和反射库的 <:<
运算符都必须解决此问题以检查可分配性;我假设反射函数 API 已经解决了我的问题。但我没有找到它。
Y假设它是def asSeenFrom(pre: Type, clazz: Symbol): Type
,但我试过了没有用。当然,我做错了什么。
这是回答这个问题的函数的用法示例:
import scala.reflect.runtime.universe._
val optionOfInt: Type = typeOf[Option[Int]]
val someTypeConstructor: ClassSymbol = typeOf[Some[_]].typeSymbol.asClass
val someOfInt: Type = instantiateSubclassTypeConstructor(optionOfInt, someTypeConstructor)
print(someOfInt.typeArgs) // outputs "List(Int)"
其中 instantiateSubclassTypeConstructor
是回答这个问题的函数。
/** @param baseInstantiation a class constructor instantiation. For example: {{{typeOf[Option[Int]]}}}
* @param directSubclassSymbol the [[ClassSymbol] of the class constructor we want to instantiate such that it is assignable to `baseInstantiantion`. For example: {{{typeOf[Some[_]].typeSymbol.asClass}}}
* @return a type instantiation of the class constructor referenced by the `directSubclassSymbol` such that it is assignable to `baseInstantiantion`. For example: {{{typeOf[Some[Int]]}}}
*/
def instantiateSubclassTypeConstructor(baseInstantiation: Type, directSubclassSymbol: ClassSymbol): Type = ???
scala 版本:2.13.3
这是部分答案。它只是找出基classX
的类型参数和直接子classY
.
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)
回答问题的缺失部分是创建 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)
}
}
一个简单的用法示例:
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]