2016-07-03 8 views
5

Ben bir Genel üst sınıf olduğunu varsayarsakScala Yansımada, bir beton alt sınıfının jenerik tip parametresi nasıl alınır?</p> <pre><code>class GenericExample[T]( a: String, b: T ) { def fn(i: T): T = b } </code></pre> <p>ve somut bir alt sınıfı:

case class Example(
        a: String, 
        b: Int 
       ) extends GenericExample[Int](a, b) 

Ben scala yansıma yoluyla fonksiyonu "fn" tipi parametresini elde etmek istiyorum, bu yüzden seçip filtre üyeleri aracılığıyla:

import ScalaReflection.universe._ 

val baseType = typeTag[Example] 

val member = baseType 
    .tpe 
    .member(methodName: TermName) 
    .asTerm 
    .alternatives 
    .map(_.asMethod) 
    .head 

    val paramss = member.paramss 
    val actualTypess: List[List[Type]] = paramss.map { 
     params => 
     params.map { 
      param => 
      param.typeSignature 
     } 
    } 

bana List(List(Int)) olan doğru sonucu vermek için scala bekliyordum, bunun yerine sadece g ot jenerik Ben typeSignature bulundu belgenin içinden Crunching List(List(T))

suçlu:

* This method always returns signatures in the most generic way possible, even if the underlying symbol is obtained from an 
* instantiation of a generic type. 

Ve alternatifi kullanmak için bana önerir: Sınıf Örneği hayır olduğundan,

def typeSignatureIn(site: Type): Type 

Ancak daha uzun jenerik, tipTag'dan [Örnek] site almamın bir yolu yok, kimse bana typeTf [Int] nasıl yazılacağını önerebilir sadece tipTag [Örnek]? Ya da bunu yapmanın bir yolu yok ve Java yansımasına geri dönmem gerekiyor mu?

Yardımlarınız için çok teşekkürler.

GÜNCELLEME: Hatta MethodSymbol.returnType, aşağıdaki kodu amaçlandığı gibi çalışmadığını tespit bazı hızlı testinden sonra: Ayrıca T verim

member.returnType 

, annd düzeltilmesi edilemez aşağıdaki kod sonucu değişmez olarak asSeenFrom tarafından,:

member.returnType.asSeenFrom(baseType.tpe, baseType.tpe.typeSymbol.asClass) 
+0

Sorunuzu okumadan önce bile. Scala ile olan tüm deneyimim boyunca, temel kavramlarından biri derleyiciye olabildiğince fazla yetki vermektir. Yani yansıma, scalada yapacağınız şeylerden biri değildir. Ancak Makroları veya bağlam sınırlarını (Manifest ve ClassManifests) kullanabilirsiniz – caeus

+0

Kullanımdan kaldırılma sürecinde Manifest mi? Ve ClassManifest ClassTag olarak yeniden adlandırıldı mı? Umarım en azından silinmiş ClassTag'ı yöntemden alabilirim, ama yine de bunu yapamaz. – tribbloid

cevap

0

: Ben Scala'nın tasarımından dolayı alternatif olmadığını düşünün:

Scala yansıması yöntemleri arasındaki temel fark & Java yansıması köreltici: Scala yöntemi compri birçok parantezin sesleri, argümanlarla bir metodu çağırmak, ilk önce sadece daha fazla parantez alabilen anonim bir sınıf oluşturur ya da daha fazla braket kalmazsa, bir Nullary Metod sınıfı oluşturur (a.k.a. yöntemin sonucunu elde etmek için çözülebilir). Bu nedenle, yöntem zaten Yöntem & NullaryMethod İmzalara ayrıldığında, scala yönteminin türleri bu düzeyde çözülür.Bunun sonucunda

sonucun türü sadece kullanılarak özyinelemeye almak olabilir ortaya çıkıyor:

private def methodSignatureToParameter_ReturnTypes(tpe: Type): (List[List[Type]], Type) = { 
    tpe match { 
     case n: NullaryMethodType => 
     Nil -> n.resultType 
     case m: MethodType => 
     val paramTypes: List[Type] = m.params.map(_.typeSignatureIn(tpe)) 
     val downstream = methodSignatureToParameter_ReturnTypes(m.resultType) 
     downstream.copy(_1 = List(paramTypes) ++ methodSignatureToParameter_ReturnTypes(m.resultType)._1) 
     case _ => 
     Nil -> tpe 
    } 
    } 

    def getParameter_ReturnTypes(symbol: MethodSymbol, impl: Type) = { 

    val signature = symbol.typeSignatureIn(impl) 
    val result = methodSignatureToParameter_ReturnTypes(signature) 
    result 
    } 

impl yöntemini sahibi sınıftır ve symbol sen scala yansıması

tarafından Type.member(s) elde budur
+0

Scala ve Java yansıma yönteminin, her ikisi de kendi avantajlarına sahip oldukları için daha fazla birlikte çalışabilir hale getirilebileceğini umuyorum: java yönteminin çağırması çok daha hızlıdır, ancak JVM'deki çalışma zamanı denetimi oldukça gevşektir, mükemmeliyet yoktur burada: - < – tribbloid

4

iki appr vardır hangi oaches Ben önerebilirsiniz:

1) taban sınıfından genel tür Ortaya:

import scala.reflect.runtime.universe._ 

class GenericExample[T: TypeTag](a: String, b: T) { 
    def fn(i: T) = "" + b + i 
} 

case class Example(a: String, b: Int) extends GenericExample[Int](a, b) {} 

val classType = typeOf[Example].typeSymbol.asClass 
val baseClassType = typeOf[GenericExample[_]].typeSymbol.asClass 
val baseType = internal.thisType(classType).baseType(baseClassType) 

baseType.typeArgs.head // returns reflect.runtime.universe.Type = scala.Int 

2) döndüren örtülü yöntemi ekleyin türü: Ben çözüm post ediyorum

import scala.reflect.runtime.universe._ 

class GenericExample[T](a: String, b: T) { 
    def fn(i: T) = "" + b + i 
} 

case class Example(a: String, b: Int) extends GenericExample[Int](a, b) 

implicit class TypeDetector[T: TypeTag](related: GenericExample[T]) { 
    def getType(): Type = { 
    typeOf[T] 
    } 
} 

new Example("", 1).getType() // returns reflect.runtime.universe.Type = Int 
+0

Benim vakalarımın çoğunda GenericExample bilinmeyen ve kalıtsal bir grafik kalıntısına gömülmüş, bu yüzden bir arkadaşı Dedektörü yazmak mümkün değil, ama ilk çözümü çözmeyi deneyeceğim, cevabınız için çok teşekkürler! – tribbloid

+0

Çalışmıyor: Hata: (72, 20) bulunamadı: iç değer val baseType = internal.thisType (classType) .baseType (baseClassType). Ben bir kütüphane – tribbloid

+0

ile uyumluluk için Scala 2.10.6 kullanıyorum Şimdi bir ipucu var, süper genel sınıftan MethodSymbol her zaman tip parametreleri silmek, bunun yerine MethodType kullanmak zorundayım. – tribbloid

İlgili konular