2017-02-04 3 views
0

스칼라 매크로에 몇 가지 문제가 있으며 생성자의 실현 유형을 식별합니다. 여기에 잘못된 것이 있거나 올바른 전화가 무엇인지 확실하지 않습니다. 설명서에서 typeSignatureIn과 같이 정확한 정보를 반환해야합니다. ClassTag [Int],하지만 매크로를 실행할 때, 실제로 U가 실현 된 형식이 아닌 형식 매개 변수이므로 컴파일에 실패한 ClassTag [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 [지능]을 얻을 필요가, 어떤 아이디어?

답변

0

형식을 해결할 때마다 dealias을 사용해보세요. Scala는 참조하는 내용을 알고있을 때에도 참조를 유지합니다. dealias은 참조가 대체 된 유형의 사본 (?)을 가져옵니다.

또한 scala.reflect.macros.Context이 아닌 blackbox 또는 whitebox 매크로를 선택해야합니다.

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]))) 
+0

많은 감사를 :

이것은 작동하는 것 같다. 그것을 더 넓은 코드베이스에 통합하기 위해 아직 고심하고 있지만, 다음에 조사 할 것이 무엇인지 잘 알고 있습니다. –

관련 문제