如何使用泛型类型部分应用(或咖喱)更高的订单?

时间:2015-07-26 22:49:57

标签: scala generics

TL; DR

我认为我的TL; DR是如何部分泛型函数的?但是,我已经添加了尝试和帮助的细节。我已经尝试过谷歌搜索,但我对Scala来说还是比较新的,所以我认为我缺少一两个学期。

背景

我试图减少样板,我遇到了似乎无法弄清楚Scala语法的情况。我有一个围绕Future的包装,看起来像:

// Wrapper for a block that sends timing data to statsd using a Stats class
object Timed {
  def apply[A](key: String, maybeStat: Option[Stats] = None)(block: => A): A = {
    val stat = maybeStat.getOrElse(Stats())
    val start = DateTime.now()
    val out = block
    stat.time(key, new Duration(start, DateTime.now()).getMillis)
    out
  }
}

object TimedFuture {
  def apply[A](key: String, maybeStat: Option[Stats] = None)(block: => A)(
    implicit executionContext: ExecutionContext
  ): Future[A] = Future {
    Timed(key, maybeStat)(block)
  }
}

然后我的服务看起来像:

class ThingsServiceImpl @Inject() (
  private val database: Database,
  private implicit val executionContext: ExecutionContext
) extends ThingsService {
  private val stat = Stats.withPrefix("services.things")

  override def findThings(ids: Long*): Future[Seq[Thing]] = TimedFuture("find_things", Option(stat)) {
    // Find the things using a sync DB connection :-/
  }
}  

我想通过添加类似以下内容的行来删除Option(stat)对所有TimedFuture次调用的尴尬附加参数:

// Context
) extends ThingsService {
  private val stat = Stats.withPrefix("services.things")
// End context

  private val TimedFuturePartialed = TimedFuture(_, Option(stat))

所以我可以像以下一样使用它:

override def findThings(ids: Long*): Future[Seq[Thing]] = TimedFuturePartialed("find_things") {

这里的目标是我想让statsd中的时间看起来像:"services.things.find_things"而不是重复自己。

我上面尝试的东西和IntelliJ的自动输入显示了我:

private val TimedFutureP: (String) => (Nothing) => Future[Nothing] = TimedFuture(_, Option(stat))

但是,这种类型不够通用。

1 个答案:

答案 0 :(得分:1)

您可以TimedFuturePartialed使用泛型方法(或使用通用apply方法的对象,几乎相同)。

private def TimedFuturePartialed[A](block: => A) = TimedFuture(block, Option(stat))

这种方式block不会被推断为Nothing。也就是说,如果你想保持它的通用性,你就不能丢失类型参数。

或者,如果您尝试做的只是避免明确传递Option[Stats],您可以尝试将其隐含。

object TimedFuture {
  def apply[A](key: String)(block: => A)(implicit ec: ExecutionContext, maybeStat: Option[Stats] = None): Future[A] = Future {
    Timed(key, maybeStat)(block)
  }
}

如果您的每个对象都定义了自己的Option[Stats],这将可以正常工作,但如果您有多个这样的浮动,可能会导致问题(即模糊含义,错误解决的结果令人惊讶)任何对象周围。