스칼라 반사는 실제로 복잡합니다. 여기에는 유형 기호와 거울이 들어 있습니다. 그들 사이의 관계를 말해 줄 수 있습니까?타입 심볼과 스칼라 반사 미러의 관계
답변
스칼라 리플렉션 API로 작업 할 때 Java Reflection API를 사용한 경우 익숙한 유형이 훨씬 많습니다. 당신은 클래스의 정규화 된 클래스 이름을 포함하는 String
로 시작 예제 시나리오 감안할 때, 이러한 발생할 가능성이있는 유형은 다음과 같습니다
-
는
Universe : 스칼라는 두 런타임을 지원하며, 시간의 반사를 컴파일합니다. 해당 유니버스에서 가져 와서 수행중인 리플렉션의 종류를 선택합니다. 런타임 리플렉션의 경우 이것은
scala.reflect.runtime
패키지에 해당하며 컴파일 시간 반영을 위해서는scala.reflect.macros
패키지에 해당합니다. 이 대답은 전자에 초점을 맞 춥니 다.Java와 마찬가지로 일반적으로 어떤 ClassLoader 클래스를 반영할지 선택하여 반성을 시작합니다. 스칼라는 현재 클래스의
ClassLoader
을 사용하기위한 지름길을 제공합니다 :scala.reflect.runtime.currentMirror
,Mirror
(나중에 미러에 대한 자세한 내용)을 제공합니다. 많은 JVM 응용 프로그램은 단 하나의 클래스 로더 만 사용하므로 Scala Reflection API의 일반적인 시작점입니다.runtime
에서 가져 오기 때문에 이제 해당 유니버스에 있습니다.Symbols : 기호에는 반영하고 싶은 내용에 대한 정적 메타 데이터가 포함되어 있습니다. 이것은 당신이 생각할 수있는 모든 것을 포함합니다.이 것은 사례 클래스, 필드, 클래스, 형식 매개 변수, 추상 등입니다. 현재 어휘 범위에 의존 할 수있는 것은 쿼리 할 수 없습니다 , 예를 들어 클래스에 속한 멤버. 필드에 액세스하거나 메소드를 호출하는 것과 같이 어떤 식 으로든 반영하는 것과 상호 작용하지 않을 수도 있습니다. 메타 데이터를 쿼리 할 수 있습니다.
클래스의 멤버는 어휘 범위에 따라 어떻게 다릅니 까? 하나의 추상 클래스 인
def foo: String
을 상상해보십시오.foo
이라는 이름은def
에 바인드 될 수 있으며 (MethodSymbol
은 쿼리해야 함) 다른 문맥에서는val
에 바인드 될 수 있습니다 (TermSymbol
). 기호로 작업 할 때 명시 적으로 예상 상징의 종류를 명시해야하는 것이 일반적이다, 당신은 우리가 시작String
예를 계속 방법.asTerm
,.asMethod
,.asClass
등을 통해이 작업을 수행.
Mirror
을 사용하여currentMirror.staticClass(myString)
클래스를 설명하는ClassSymbol
을 파생시킵니다.Types : 유형을 사용하면 기호가 현재 어휘 문맥에서 참조하는 유형에 대한 정보를 조회 할 수 있습니다. 일반적으로
Type
을 두 가지 용도로 사용합니다. 즉, 어떤 vars, val 및 def가 있는지 쿼리하고 유형 관계를 쿼리하는 것입니다 (예 :이 유형이 해당 유형의 하위 클래스 임).Type
을 잡는 방법에는 두 가지가 있습니다.TypeSymbol
(ClassSymbol
은TypeSymbol
) 또는TypeTag
입니다.예를 계속하면 심볼
.toType
을Type
으로 가져와야합니다.Scopes : 당신이
.members
또는.decl
-이에 대한Type
을 물어 보면 당신이 용어 (바르 및 발스)와주는 것입니다 방법을-현재 어휘 범위 내에서 회원의Symbol
의 목록을 얻을. 이 목록은MemberScope
유형으로 유지되며, 이는 단지 영광을 얻은List[Symbol]
입니다.위의 추상 클래스의 예에서이 목록에는 현재 범위에 따라
foo
이름의TermSymbol
또는MethodSymbol
이 포함됩니다.- Names :
TermName
및TypeName
: 이름은 두 가지 종류로 왔습니다. 그것은 단지String
의 래퍼입니다. 유형을 사용하여 이름이Name
인 것을 판별 할 수 있습니다. - Mirrors : 마지막으로 미러는 "무언가"와 상호 작용하는 데 사용됩니다. 일반적으로
Symbol
으로 시작한 다음 해당 기호를 사용하여 상호 작용하려는 메서드, 생성자 또는 필드의 심볼을 가져옵니다. 필요한 기호가 있으면currentMirror
을 사용하여 기호에 대한 거울을 작성하십시오. 미러를 사용하면 생성자 (ClassMirror
)를 호출하고 필드 (FieldMirror
)에 액세스하거나 메소드 (MethodMirror
)를 호출 할 수 있습니다. 미러를 사용하여 반영되는 것에 대한 메타 데이터를 쿼리 할 수 없습니다.
:// Do runtime reflection on classes loaded by current ClassLoader val currentMirror: universe.Mirror = scala.reflect.runtime.currentMirror // Use symbols to navigate to pick out the methods and fields we want to invoke // Notice explicit symbol casting with the `.as*` methods. val classSymbol: universe.ClassSymbol = currentMirror.staticClass("com.example.Foo") val constructorSymbol: universe.MethodSymbol = classSymbol.primaryConstructor.asMethod val fooSymbol: Option[universe.TermSymbol] = classSymbol.toType.members.find(_.name.toString == "foo").map(_.asTerm) // Get mirrors for performing constructor and field invocations val classMirror: universe.ClassMirror = currentMirror.reflectClass(classSymbol) val fooInstance: Foo = classMirror.reflectConstructor(constructorSymbol).apply().asInstanceOf[Foo] val instanceMirror: universe.InstanceMirror = currentMirror.reflect(fooInstance) // Do the actual invocation val fooValue: String = instanceMirror.reflectField(fooSymbol.get).get.asInstanceOf[String] println(fooValue) // Prints the value of the val "foo" of the object "fooInstance"
그래서 함께 예를 가하고 위의 설명을 반영, 이것이 당신이 필드를 검색 생성자를 호출하고 val
을 읽을 것 어떻게, 정규화 된 클래스 이름을 가진 String
을 부여