簡體   English   中英

使用宏獲取Scala類的實現類型

[英]Obtaining the realised type for a Scala Class using macros

我在使用scala宏和確定構造函數的實現類型時遇到一些問題。 不知道我在這里做錯了什么還是正確的電話。 從文檔看來, typeSignatureIn應該返回正確的信息,例如ClassTag [Int],但是當我運行宏時,我實際上得到ClassTag [U],由於U是類型參數,而不是已實現的類型,因此無法編譯。

import scala.language.experimental.macros
import scala.reflect.ClassTag
import scala.reflect.macros.Context

def macroImpl[T: c.WeakTypeTag](c: Context) = {
  import c.universe._

  val typeToMock = weakTypeOf[T]

  val primaryConstructorOpt = typeToMock.members.collectFirst {
    case method: MethodSymbolApi if method.isPrimaryConstructor => method
  }

  val constructorArgumentsTypes = primaryConstructorOpt.map { 
    constructor =>
    val constructorTypeContext = constructor.typeSignatureIn(typeToMock)
    val constructorArguments = constructor.paramss
    constructorArguments.map { symbols =>
      symbols.map(_.typeSignatureIn(constructorTypeContext))
    }
  }

  println(typeToMock)
  println(constructorArgumentsTypes)

  c.literalUnit
}

def foo[T] = macro macroImpl[T]

class Foo[U: ClassTag]

foo[Foo[Int]]

運行它:

scala> foo[Foo[Int]]
Foo[Int]
Some(List(List(), List(scala.reflect.ClassTag[U]))

我需要以某種方式獲取ClassTag [Int],以便稍后能夠生成正確的Tree,有什么想法嗎?

嘗試在您解析類型的每個位置使用dealias 即使知道引用的內容,Scala也會將引用保持在原位。 dealias會為您提供替換了引用的類型的副本(?)。

您還應該選擇blackbox或whitebox宏,而不僅僅是scala.reflect.macros.Context

這似乎可行:

import scala.language.experimental.macros
import scala.reflect.ClassTag
import scala.reflect.macros.whitebox.Context

def macroImpl[T: c.WeakTypeTag](c: Context) = {
  import c.universe._

  val typeToMock = weakTypeOf[T].dealias

  val primaryConstructorOpt = typeToMock.members.collectFirst {
    case method: MethodSymbolApi if method.isPrimaryConstructor => method
  }

  val constructorArgumentsTypes = primaryConstructorOpt.map { constructor =>
    val constructorTypeContext = constructor.typeSignatureIn(typeToMock).dealias
    val constructorArguments = constructorTypeContext.paramLists
    constructorArguments.map { symbols =>
      symbols.map(_.typeSignatureIn(constructorTypeContext).dealias)
    }
  }

  println(typeToMock)
  println(constructorArgumentsTypes)

  q"()"
}

def foo[T]: Any = macro macroImpl[T]

class Foo[U: ClassTag]

foo[Foo[Int]]

結果

Foo[Int]
Some(List(List(), List(scala.reflect.ClassTag[Int])))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM