2017-10-25 4 views
0

Ich habe ein paar Methoden auf einem Merkmal wie so:Scala - beschränken gattungsgemäßen Art auf etwas anderes als Zukunft

trait ResourceFactory[+R] { 

    def using[T](work: R => T): T 

    def usingAsync[T](work: R => Future[T]): Future[T] 

} 

Leider gibt es nichts in der Art checker Sie zu stoppen die erste using Methode mit einem Aufruf der Funktion Zurückgeben einer Future. Ich möchte, dass der Compiler darauf besteht, dass der Typ T in der ersten Methode etwas anderes als Future ist, um diesen Fehler zu verhindern - ist das möglich?

import scala.concurrent.Future 
import shapeless._ 

trait ResourceFactory[+R] { 
    def using[T](work: R => T)(implicit ev: T <:!< Future[_]): T = ??? 
    def usingAsync[T](work: R => Future[T]): Future[T] = ??? 
} 

Dann:

Dank

+1

Ich habe [dies] (https://stackoverflow.com/questions/6909053/enforce-type-difference) verwendet, um ehrlich zu sein, nicht sicher, dass es mit höheren Arten arbeiten wird. –

Antwort

2

können Sie shapeless' <:!< verwenden

scala> val r = new ResourceFactory[Int] {}   
r: ResourceFactory[Int] = [email protected]    

// Compiles (the error is due to the use of ???) 
scala> r.using(_.toString) 
scala.NotImplementedError: an implementation is missing               

// Doesn't compile 
scala> r.using(Future.successful(_))     
<console>:17: error: ambiguous implicit values:  
both method nsubAmbig1 in package shapeless of type [A, B >: A]=> shapeless.<:!<[A,B]      
and method nsubAmbig2 in package shapeless of type [A, B >: A]=> shapeless.<:!<[A,B]      
match expected type shapeless.<:!<[scala.concurrent.Future[Int],scala.concurrent.Future[_]]    
     r.using(Future.successful(_)) 
+0

Danke, das funktioniert wunderbar. Der einzige Schmerzpunkt ist, dass ich den impliziten Beweis zu jeder Implementierung des Merkmals hinzufügen muss. –

0

Hier ist eine Alternative, die ich von https://github.com/japgolly/scalajs-react/blob/cb75721e3bbd0033ad63d380bcaddc96fbe906e3/core/src/main/scala/japgolly/scalajs/react/Callback.scala#L21-L31 schamlos gestohlen habe:

@implicitNotFound("You're returning a ${A}, which is asynchronous, which means the resource may be closed before you try and use it. Instead use usingAsync.") 
final class NotFuture[A] private[ResourceFactoryTests]() 
object NotFuture { 
    final class Proof[A] private[ResourceFactory]() 
    object Proof { 
    implicit def preventFuture1[A]: Proof[Future[A]] = ??? 
    implicit def preventFuture2[A]: Proof[Future[A]] = ??? 
    @inline implicit def allowAnythingElse[A]: Proof[A] = null 
    } 
    @inline implicit def apply[A: Proof]: NotFuture[A] = null 
} 

die als verwendet werden können:

trait ResourceFactory[+R] { 
    def using[T: ResourceGuard](work: R => T): T 
    def usingAsync[T](work: R => Future[T]): Future[T] 
} 

Dies hat den Vorteil, dass nicht jedes Mal die implizite arg hinzufügen zu müssen Sie die Methode implementieren, aber den Nachteil, dass ich reine Fracht culting bin - ich verstehe nicht, warum es funktioniert, obwohl es ähnliche Prinzipien zu formlos zu verwenden scheint.

Verwandte Themen