Методы расширения:
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]]
В зависимости от того, сколько вам нужно гибкости, вы можете использовать простой метод расширения или - если вы хотите иметь возможность использовать их со многими другими типами и генерировать реализацию на основе некоторых принципов - с помощью класса типов. Для начала попробуйте первое, и только если вам понадобится расширяемость go для второго. Если вы хотите узнать больше, узнайте больше о: последствиях, методах расширения и классах типов.