Scala - 将泛型类型限制为Future以外的任何类型

时间:2017-10-25 09:42:53

标签: scala

我有一些关于特征的方法:

Error while trying to load the project '/home/emma/Documents/My-App/My-App/My-App.csproj': Unknown ToolsVersion '15.0'

很遗憾,类型检查器中没有任何内容可以阻止您使用返回trait ResourceFactory[+R] { def using[T](work: R => T): T def usingAsync[T](work: R => Future[T]): Future[T] } 的函数调用第一个using方法。我希望编译器坚持第一种方法中Future的类型不是T,以防止出现错误 - 这可能吗?

由于

2 个答案:

答案 0 :(得分:2)

您可以使用shapeless' <:!<

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] = ???
}

然后:

scala> val r = new ResourceFactory[Int] {}           
r: ResourceFactory[Int] = $anon$1@effe6ad            

// 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(_))   

答案 1 :(得分:0)

这是我从https://github.com/japgolly/scalajs-react/blob/cb75721e3bbd0033ad63d380bcaddc96fbe906e3/core/src/main/scala/japgolly/scalajs/react/Callback.scala#L21-L31无耻地偷走的另一种选择:

@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
}

可以用作:

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

这样做的好处是不必在每次实施方法时都添加隐式arg,但缺点是我是纯粹的货物结果 - 我不明白为什么它有效,尽管它似乎使用类似的原则来不成形。