微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

找出类型构造函数的类型参数,知道其扩展的类型构造函数的类型参数

如何解决找出类型构造函数的类型参数,知道其扩展的类型构造函数的类型参数

X是具有类型参数A1A2,...,An的类型构造函数。例如Option[A]Function1[A1,A2]

X[T1,T2,...,Tn]为通过将类型构造函数X应用于具体的类型自变量T1T2,... Tn而得到的类型。例如Option[Int]Function1[Long,List[String]]

YX的直接子类,它使X的某些类型参数不固定,不添加新的自由类型参数,并且其类型参数为{{1 }},B1,...,B2Bm。例如m <= nSome[B]

我需要实现一个函数,该函数找出要分配给类型参数PartialFunction[B1,B2],{的具体类型R1R2,...,Rm类型构造函数B1的{​​1}},...,B2,这样Bm的所有差异均被删除(所有特征和类均视为非变异)。

对于YY[R1,R2,Rm] <:< X[T1,Tn],很明显Option对于Some的{​​{1}}除去了方差是正确的。 同样,在R1 = T1Some[R1] <:< Option[T1]的情况下,显然Function1的{​​{1}}和PartialFunction的方差已删除。 但是对于一般情况,情况要复杂一些。

鉴于编译器和反射库的R1 = T1运算符都必须解决此问题才能检查可分配性;我认为反射API的功能已经解决了我的问题。但我找不到。 是的,它应该是R2 = T2,但是我没有用。当然,我做错了。

这是回答此问题的函数用法示例:

PartialFunction[R1,R2] <:< Function[T1,T2]

<:<是回答此问题的函数

def asSeenFrom(pre: Type,clazz: Symbol): Type

scala版本:2.13.3

解决方法

这是部分答案。它仅找出基类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)

缺少该问题的部分是创建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,B1] {}

scala> applySubclassTypeConstructor(
    typeOf[X[Long,_]].typeConstructor
)
val res2: reflect.runtime.universe.Type =
    Y[String,Long]

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。