nasıl

2015-11-04 23 views
5

bir genel işlevi dikkate derleme zamanında olmayan genel tür uygulamak?nasıl

var actorReceive: Receive = PartialFunction.empty 
def addCase[T](handler: T => Boolean): Unit = { 
    actorReceive = actorReceive orElse ({ 
     case msg: T => // call handle at some point, plus some other logic 
      handler(msg) 
    }) 
} 

addCase fonksiyonu gibi ClassTag isteyerek çözülebilir tip silme uyarısı, neden olacaktır:


ben çözmek istiyorum ast sorun böyle bir şeydir def addCase[T: ClassTag](..., ama yine de ClassTag

addCase[List[Int]](_ => {println("Int"); true}) 
addCase[List[String]](_ => {println("String"); false}) 

actorReceive(List("str")) // will print "Int" 

yukarıdaki kodyazdırır: gibi aramalar karşı korumak olamazherhangi bir uyarı veya hata vermeden, herhangi bir çıkış yolu var mı? aşağıdaki gibi

+3

Burada akka ile uğraştığınız için, 'genel' iletileri yapmaya çalışmanın, özellikle herhangi bir tür bir serileştirme devam ediyor. Daha genel bir düzeyde, Int ve List [Int] türünün her ikisi de *, yani başka hiçbir kısıtlamaya sahip olmayan tek bir tip parametresi bunları ayırt etmeyecektir. Standart bir typeclass çözümü muhtemelen yeterli olacaktır ya da sağlanan link dk14 gibi daha gelişmiş bir şey kullanabilirsiniz. – melps

+1

"List" ten koruma ekleyebilirsiniz: http://stackoverflow.com/questions/15962743/using-context-bounds-negionally-to-ensure-type-class-instance-is-absent-from-s – dk14

+0

Ancak Herhangi bir polimorfik tip – dk14

cevap

5

Bunu tür sistemde olduğu gibi yansıma olmadan da uygulamak için bir yolu yoktur.

Bunu yapmanın en iyi yolu, bir türün çalışma zamanında silinecek türde bir parametresi olmadığını gösteren NonEraseable[A] gibi bir tür sınıfına sahip olmaktır. Kapsam içinde bir örtülü NonEraseable[A], A'un hiçbir tür parametresi içermediği anlamına gelmelidir.

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

trait NonEraseable[A] 

object NonEraseable { 

    implicit def ev[A]: NonEraseable[A] = macro evImpl[A] 

    def evImpl[A](c: Context)(implicit tt: c.WeakTypeTag[A]): c.Expr[NonEraseable[A]] = { 
     import c.universe._ 
     val tpe = weakTypeOf[A] 
     if(tpe.dealias.typeArgs.isEmpty) 
      c.Expr[NonEraseable[A]](q"new NonEraseable[$tpe] {}") 
     else 
      c.abort(c.enclosingPosition, s"$tpe contains parameters that will be erased at runtime.") 
    } 

} 

Kullanım örneği: Bu kullanma

def onlySimple[A : NonEraseable](value: A): Unit = println(value) 

scala> onlySimple(1) 
1 

scala> onlySimple(List(1, 2, 3)) 
<console>:13: error: List[Int] contains parameters that will be erased at runtime. 
     onlySimple(List(1, 2, 3)) 
       ^

, derleme anında bir tür parametresi de zorlayabilir bunlar görünce el işi yapabilir örtük bir makro oluşturmak için sıkıcı olurdu Bağlantılı NonEraseable olan A, istediğiniz türde türüdür. (Hile yapmadığınızı varsayar ve tür sınıfının örneğini el ile oluşturduğunuz varsayılır)

3

En az çalışma zamanında başarısız olmasına alabilirsiniz:

def addCase[T: ClassTag](handler: T => Boolean): Unit = 
    if (classTag[T].runtimeClass.getTypeParameters.nonEmpty) { 
    // throw an exception 
    } else { 
    // the main code 
    } 

Derleme zamanı hatası (, denenmemiş yaklaşık) bir işlevi yerine bir macro kullanılarak elde edilebilir:

def addCase[T](handler: T => Boolean): Unit = macro addCaseImpl 

def addCaseImpl[T: c.WeakTypeTag](c: Context)(handler: c.Expr[T => Boolean]): c.Expr[Unit] = 
    if (c.weakTypeOf[T].typeParams.nonEmpty) { 
    c.abort(c.enclosingPosition, "Generic types not allowed in addCase") 
    } else { 
    // generate code for main line 
    } 
+0

"+1", ancak makro için fazla sert değil, hatta aynı modülde test edemezsiniz. Belki de bazı shapeless tabanlı bir çözüm var. Not; Kanıt temelli birçok denemeyi denedim, ama işe yaramadı çünkü scala'nın jenerik ve yüksek mertebeden desteği oldukça garip.Bunun gibi nedenlere izin verilir: örtük def notSimple [T, M [_]] (t: M [T]) = ""; notSimple (9) 'Dönüş türünü' M [T] 'ye çevirmek derleyiciyi öldürdü. ***** 9 M [T] nasıl? :) – dk14