如何通过块类型重载 Scala 方法?

发布于 2024-11-14 20:51:27 字数 1136 浏览 2 评论 0原文

我仍在研究我的 ScalaTest FeatureSpec DSL。

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

A. A block block: =>;稍后执行的单元

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

B. 一个块block: Any =>稍后使用标记执行的单元

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

C. 无块,其中标记由另一个函数处理

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

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

I'm still working on my ScalaTest FeatureSpec DSL.

I'd like 3 variants of my given function. All take tokens: Any, and then either

A. A block block: => Unit that is executed later

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

B. A block block: Any => Unit that is executed later with the tokens

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

C. No block, where the tokens are processed by another function

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

Now when I define all three methods

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

The compiler considers them ambiguous.

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

How can disambiguate, or write a single method that can differentiate between the block (or lack of)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

烂柯人 2024-11-21 20:51:27

我喜欢上面@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
  }
}

I like @MachAndy's solution above, except for the importing of the unit2emptyfunction conversions, which I see as possibly interfering or covering other type errors.

If instead you define the following:

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

Then, you can simply:

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
  }
}
凹づ凸ル 2024-11-21 20:51:27

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

我使用了一个 given 方法作为入口,并隐式提供或不提供主体

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

首先这里是一个 sugar ,能够使用 Unit 块作为a 任意 => 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])

I have here a solution but I think it can be enhanced.

I used a single given method as entry and implicit to provide or not a body

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

First here is a sugar to be able use a Unit block as a Any => Unit

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

To be able to work in the C case, I provide a default body to fill the block parameter that does nothing.

implicit val doNothing: Any => Unit = { }

Now you can use it in this way :

/*
 * 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])
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文