如何按块类型重载Scala方法?

时间:2011-06-09 16:19:58

标签: scala dsl

我仍在使用我的ScalaTest FeatureSpec DSL。

我想要given函数的3个变体。全部取tokens: Any,然后

一个。稍后执行的块block: => Unit

given("user visits", the[AdminHomePage]) {
    // just code 
}

B中。稍后使用令牌执行的块block: Any => Unit

given("user visits", the[AdminHomePage]) { 
  x: Any => x match { 
    case ("user visits", pageClass:Class[Page]) => 
      startPage(pageClass)
  }
}

℃。没有块,其中令牌由另一个函数处理

given("user visits", the[AdminHomePage])

现在我定义所有三种方法

def given(tokens: Any) = ...
def given(tokens: Any)(block: Any => Unit) = block(tokens)
def given(tokens: Any)(block: => Unit) = block

编译器认为它们不明确。

ambiguous reference to overloaded definition, both method given in trait GivenWhenThenFeatureSpec of type (tokens: Any)(block: => Unit)Unit and  method given in trait GivenWhenThenFeatureSpec of type (tokens: Any)(block: (Any) => Unit)Unit match argument types

如何消除歧义,或者编写一个可以区分块(或缺少)的方法?

2 个答案:

答案 0 :(得分:2)

我喜欢上面的@ MachAndy解决方案,除了导入unit2emptyfunction转换,我认为这可能会干扰或覆盖其他类型的错误。

如果您定义以下内容:

object Given {
  trait Processor {
    def process(tokens: Any) 
  }
  class ProcessorA(block: =>Unit) extends Processor {
    def process(tokens: Any) = {
      block  // execute or store block for later, ignoring tokens
    }
  }
  class ProcessorB(block: Any=>Unit) extends Processor {
    def process(tokens: Any) = {
      block(tokens) // or store block for later execution
    }
  }
  class ProcessorC extends Processor {
    def process(tokens: Any) = {
      // do something defaultish with the tokens
    }
  }

  implicit def blockToProcessorA(block: =>Unit) = new ProcessorA(block)
  implicit def blockToProcessorB(block: Any=>Unit) = new ProcessorB(block)
  implicit val processorC = new ProcessorC

  def given(tokens: Any)(implicit p: Processor) = p.process(tokens)
}

然后,你可以简单地说:

import Given._

given("user visits", the[AdminHomePage])
given("user visits", the[AdminHomePage]) {
  // some stuff that ignores tokens
}
given("user visits", the[AdminHomePage]) { x: Any =>
  x match {
    // do something that looks at the tokens
  }
}

答案 1 :(得分:1)

我在这里有一个解决方案,但我认为它可以得到增强。

我使用单个given方法作为条目,隐式提供或不提供正文

def given[A](tokens: A)(implicit block: A => Unit) {
    block(tokens)
}

首先, sugar 可以使用Unit块作为Any => Unit

implicit def unit2emptyfunction(body: Unit): Any => Unit = {
    case _ => body
}

为了能够在C情况下工作,我提供了一个默认体来填充什么都不做的block参数。

implicit val doNothing: Any => Unit = { }

现在您可以这样使用它:

/*
 * A case, block is implicitly converted into a A => Unit 
 * although it doesn't use the argument
 */
given("user visits", the[AdminHomePage]) {
    // just code
}


/*
 * B case, block is fully provided and thus not implicitly converted
 */ 
given("user visits", the[AdminHomePage]) {
  case ("user visits", pageClass: Class[Page]) => 
      startPage(pageClass)
}

// C case, block implicitly provided by doNothing implicit val
given("user visits", the[AdminHomePage])