选择和未来

时间:2013-04-01 10:18:15

标签: scala scala-option

我正在使用惊人数量的抽象来构建ubercool应用程序。 现在我将设计过度设计的EntityGetService。

我想要的第一件事是很多抽象类型,比如说:

trait EntityGetService[ID, ENTITY, CONTAINER] {
  def get(id: ID): CONTAINER
}

这里的CONTAINER是包含(或不包含)请求实体的东西的类型。与Option [ENTITY]非常相似。但我想要的第二件事,那个CONTAINER也可以成为未来[ENTITY]。

所以我真想写这样的特质:

trait EntityGetService[ID, ENTITY, CONTAINER <: Wrapper[ENTITY]] {
    def get(id: ID): CONTAINER
}

并以这种方式指定:

trait EntitySyncGetService[Long, Entity, Option[Entity]] {
    def get(id: Long): Option[Entity]
}

trait EntityAsyncGetService[Long, Entity, Future[Entity]] {
    def get(id: Long): Future[Entity]
}

有没有办法在不重新扩展或混合选项和未来的情况下做到这一点?

看起来Option和Future有一些共同点(它们的两个容器)。它与monads有关吗?

或者这只是我失眠的产物?

2 个答案:

答案 0 :(得分:3)

不评论这一切的合理性,您可以使用更高阶的类型:

trait WrappedGetService[ID, ENTITY, WRAPPER[_]] {
  def get(id: ID) : WRAPPER[ENTITY]
}

然后您可以声明WrappedGetService[Long, Entity, Option]

更新:一些参考

该功能称为高阶类型(可能还有高级类型)或类型构造函数

  • the language specification中,它应该主要出现在部分中 4.4,类型参数,但不会有太多关于它,它的工作方式与其他类型参数非常相似。
  • 该功能最初是在论文Generics of a higher kind中提出的。该论文可能无法完全按照原样实现 语言,但它应该非常接近。另一方面,集合库又采用了另一种方式,您可以在Fighting Bit Rot with Types中看到原因。
  • 您可以查看scalaz库(不适合胆小的人)。如果你这样做,你可能也想看看Haskell。

答案 1 :(得分:3)

你可以通过我称之为“手动AOP”的一点来实现这一点。

首先定义一些基本特征,以捕获将结果包装在OptionFuture或任何其他容器中的概念,以及实际执行包装的方法:

import concurrent._

trait AbstractService {
  type Result[T]
  protected def result[T]( code: => T ) : Result[T]
}

然后为FutureOption案例专门化这个基本特征:

trait SyncService extends AbstractService {
  type Result[T] = Option[T]
  // Returns the original result wrapped in Some, 
  // or None if it was null or an exception occured
  protected def result[T]( code: => T ) : Option[T] = {
    try {
      Option( code )
    } catch{ case ex: Throwable =>
      ex.printStackTrace()
      None
    }
  }  
}

trait AsyncService extends AbstractService {
  type Result[T] = Future[T]
  protected val execContext: ExecutionContext
  protected def result[T]( code: => T ) : Future[T] = {
    future( code )( execContext )
  }
}

现在你很高兴能够定义你的EntityGetService特性:

trait EntityGetService[ID, ENTITY] extends AbstractService {
  def get( id: ID ): Result[ENTITY] = result {
    ???
  }

  // add all the other method implementations here, taking care to 
  // wrap the method bodies inside "result"
}

// Now specializing EntityGetService as a sync or async service is just a matter 
// of mixing SyncService or AsyncService:

class EntitySyncGetService[Long, Entity] extends EntityGetService[Long, Entity] with SyncService
class EntityAsyncGetService[Long, Entity]( implicit val execContext: ExecutionContext ) extends EntityGetService[Long, Entity] with AsyncService