需要函数参数实现方法 - Scala
Require Function Parameters Implement Method - Scala
有没有一种方法可以要求传递给函数的对象实现一组核心方法?
例如,我希望能够编写一个求和方法来对实现“+”运算符的任何可迭代对象求和。
我的初步实现如下
trait addable[T <: addable[T]]{
def +(other: T): T
}
def sum[T <: addable[T]](items: Iterable[T]) =
if(items.isEmpty) throw new Exception("Can't sum nothing")
else items.tail.foldRight(items.head)(_+_)
//Starst with the first element and adds all other elements to it
现在这个方法行得通,但是很笨拙。如果我想让某些东西可以求和,我必须在我想求和的每个 class 中显式实现 addable[T],更不用说为数字类型和字符串定义一堆显式转换了。
有没有办法让它看起来像这样?
def sum[T fulfills addable[T]](items: Iterable[T]) =
if(items.isEmpty) throw new Exception("Can't sum nothing")
else items.tail.foldRight(items.head)(_+_)
或者,是否有一些设计模式可以消除对此的需求(我现在有效地做的似乎只是适配器模式)?
做这种事情的常见模式是使用类型类:http://typelevel.org/cats/typeclasses.html
这是您的用例的 Addable
类型类的示例实现:
trait Addable[T] {
def +(a: T, b: T): T
}
// Among other places Scala searches for implicits
// in the companion objects of the relevant classes.
// Read more in this answer:
object Addable {
// Using context bound notation
def apply[T : Addable]: Addable[T] = implicitly
// Instance of Addable typeclass for types,
// that have an instance of the built-in Numeric typeclass
implicit def numeric[T : Numeric]: Addable[T] = {
import Numeric.Implicits._
// This uses Scala 2.12 feature of automatic convertions of lambdas to SAMs
// You can create an instance of an anonymous subclass in older versions.
_ + _
}
// Instance of Addable for all kinds of Iterables,
// that adds them element by element (like mathematical vectors)
implicit def iterable[That, T](implicit
ev: That <:< IterableLike[T, That], // To compute the element type T from That
cbf: CanBuildFrom[That, T, That], // To call `map` method
add: Addable[T] // To add elements of the iterable
): Addable[That] =
(a, b) => (a, b).zipped.map(add.+)
}
这里是 sum
方法的示例实现,它使用了这个 Addable
类型类:
def sum[T : Addable](items: Iterable[T]): T = items.
reduceOption(Addable[T].+).
getOrElse(throw new Exception("Can't sum nothing"))
以及一些使用它的结果:
scala> sum(Seq(1.2, 3.4, 5.6))
res0: Double = 10.2
scala> sum(Seq(Vector(1,2), Vector(4,5), Vector(6,7)))
res1: scala.collection.immutable.Vector[Int] = Vector(11, 14)
有没有一种方法可以要求传递给函数的对象实现一组核心方法?
例如,我希望能够编写一个求和方法来对实现“+”运算符的任何可迭代对象求和。
我的初步实现如下
trait addable[T <: addable[T]]{
def +(other: T): T
}
def sum[T <: addable[T]](items: Iterable[T]) =
if(items.isEmpty) throw new Exception("Can't sum nothing")
else items.tail.foldRight(items.head)(_+_)
//Starst with the first element and adds all other elements to it
现在这个方法行得通,但是很笨拙。如果我想让某些东西可以求和,我必须在我想求和的每个 class 中显式实现 addable[T],更不用说为数字类型和字符串定义一堆显式转换了。
有没有办法让它看起来像这样?
def sum[T fulfills addable[T]](items: Iterable[T]) =
if(items.isEmpty) throw new Exception("Can't sum nothing")
else items.tail.foldRight(items.head)(_+_)
或者,是否有一些设计模式可以消除对此的需求(我现在有效地做的似乎只是适配器模式)?
做这种事情的常见模式是使用类型类:http://typelevel.org/cats/typeclasses.html
这是您的用例的 Addable
类型类的示例实现:
trait Addable[T] {
def +(a: T, b: T): T
}
// Among other places Scala searches for implicits
// in the companion objects of the relevant classes.
// Read more in this answer:
object Addable {
// Using context bound notation
def apply[T : Addable]: Addable[T] = implicitly
// Instance of Addable typeclass for types,
// that have an instance of the built-in Numeric typeclass
implicit def numeric[T : Numeric]: Addable[T] = {
import Numeric.Implicits._
// This uses Scala 2.12 feature of automatic convertions of lambdas to SAMs
// You can create an instance of an anonymous subclass in older versions.
_ + _
}
// Instance of Addable for all kinds of Iterables,
// that adds them element by element (like mathematical vectors)
implicit def iterable[That, T](implicit
ev: That <:< IterableLike[T, That], // To compute the element type T from That
cbf: CanBuildFrom[That, T, That], // To call `map` method
add: Addable[T] // To add elements of the iterable
): Addable[That] =
(a, b) => (a, b).zipped.map(add.+)
}
这里是 sum
方法的示例实现,它使用了这个 Addable
类型类:
def sum[T : Addable](items: Iterable[T]): T = items.
reduceOption(Addable[T].+).
getOrElse(throw new Exception("Can't sum nothing"))
以及一些使用它的结果:
scala> sum(Seq(1.2, 3.4, 5.6))
res0: Double = 10.2
scala> sum(Seq(Vector(1,2), Vector(4,5), Vector(6,7)))
res1: scala.collection.immutable.Vector[Int] = Vector(11, 14)