DSL:在特定类型的集合的每个元素上应用功能的快捷方式

问题描述 投票:0回答:1

我是scala的新手,我正在尝试使用其强大的功能来创建简单的DSL。我发现使用DSL时可以创建类似于以下示例的内容,而我想知道如何做到这一点:

val oranges = Array.tabulate(2)(i => Orange(i+10)) //Orange(diameter)
// Oranges of diameter 10 and 11
oranges incDiameter 5
// Oranges in the array now have diameter 15 and 16

我不明白,我们如何直接将incDiameter函数应用于数组,因为我们无法将函数incDiameter添加到Array scala类;以我的理解,这等效于执行oranges.incDiameter(5),所以类似Array [Fruit] .incDiameter(5),但是由于incDiameter没有在Array类中声明,因此应该在哪里声明它,以便将第三行工作?我的直觉是,可能有一种方法可以修改函数在我们自己的类的可迭代对象上的应用方式,因此示例的第三行实际上已转换为oranges.map(_。incDiameter(5)),但我从未在任何地方看到过

scala dsl
1个回答
0
投票

扩展方法:

implicit class OrangesOps(val oranges: Array[Orange]) extends AnyVal {

  def incDiameter(by: Int): Array[Orange] = oranges.map(_.incDiameter(5))
}

如果您希望扩展方法适用于可以证明适用的任何类型,则可以使用类型类:

trait IncreasableDiameter[A] {

  def incDiamater(what: A)(by: Int): A
}

implicit class DiamatersOps[A](val what: A) extends AnyVal {

  def incDiameter(by: Int)(implicit increasable: IncreasableDiameter[A]): A =
    increasable.incDiamater(what)(by)
}

然后,如果您可以提供隐式证明类型存在类型类的实例,则可以使用incDiameter方法(只要实例和扩展方法都将被定义/导入到范围)

implicit val orangesIncreasable: IncreasableDiameter[Orange] =
  new IncreasableDiameter[Orange] {
    def incDiamater(what: Orange)(by: Int): Orange = what.incDiamater(by)
  }

implicit def arrayIncreasable[A](
  implicit increasable: IncreasableDiameter[A]
): IncreasableDiameter[Array[A]] = new IncreasableDiameter[Array[A]] {

  def incDiamater(what: Array[A])(by: Int): Array[A] = what.map(_.incDiamater(by))
}

这将使您在以下位置调用此操作:

val orange: Orange = ...
orange.incDiameter(5) // oranges built-in method
Array(orange).incDiameter(5) // no build in method, but extension method can be used
                             // because we can produce type class for Array[Orange]
Array(Array(orange)).incDiameter(5) // similar to above, we can create
                                    // type class for Array[Array[Orange]]

取决于所需的灵活性,可以使用简单的扩展方法,或者-如果您希望能够将它们与更多类型一起使用并生成实现基于一些原则-具有类型类。对于初学者,请尝试前者,并且只有在您需要可扩展性时才选择后者。如果您想了解更多,请详细了解:隐式,扩展方法和类型类。

© www.soinside.com 2019 - 2024. All rights reserved.