Ben*_*itz 10 inheritance scala scala-collections
我正在寻找一个非常简单的子类化Scala集合的例子.我对这一切是如何以及为何有效的全面解释并不感兴趣; 很多这些都可以在这里和互联网上的其他地方找到.我想知道这样做的简单方法.
下面的类可能是一个尽可能简单的例子.这个想法是,使其子类Set[Int]有一个额外的方法:
class SlightlyCustomizedSet extends Set[Int] {
def findOdd: Option[Int] = find(_ % 2 == 1)
}
Run Code Online (Sandbox Code Playgroud)
显然这是错误的.一个问题是没有构造函数可以将内容放入其中Set.CanBuildFrom必须构建一个对象,最好通过调用一些已知的库代码来知道如何构建它.我已经看到在配对对象中实现几个附加方法的示例,但它们显示了它是如何工作的或如何做更复杂的事情.我想看看如何利用库中已有的东西来解决这几行代码问题.实现这一目标的最简单,最简单的方法是什么?
Jam*_*pic 21
如果您只想将一个方法添加到类中,那么子类化可能不是最佳选择.Scala的集合库有点复杂,并且叶子类并不总是适合子类化(一个可能从子类化开始HashSet,但这会让你开始深入兔子洞的旅程).
也许实现目标的更简单方法是:
implicit class SetPimper(val s: Set[Int]) extends AnyVal {
def findOdd: Option[Int] = s.find(_ % 2 == 1)
}
Run Code Online (Sandbox Code Playgroud)
这实际上并不是Set的子类,而是创建一个隐式转换,允许您执行以下操作:
Set(1,2,3).findOdd // Some(1)
Run Code Online (Sandbox Code Playgroud)
如果你来自Java背景,那么扩展标准集合是非常困难的 - 在所有Java标准库充满了j.u.ArrayList子类之后,几乎任何可以包含其他东西的东西都是如此.但是,Scala有一个关键的区别:它的首选集合都是不可变的.
这意味着他们没有可以add就地修改它们的方法.相反,它们具有+构造新实例的方法,包括所有原始项目以及新项目.如果他们天真地实现这一点,那就非常低效,因此他们使用各种特定于类的技巧来允许新实例与原始实例共享数据.该+方法甚至可以返回与原始对象不同的对象 - 一些集合类对小集合或空集合使用不同的表示.
但是,这也意味着如果你想要继承其中一个不可变集合,那么你需要理解你正在子类化的类的内容,以确保你的子类实例的构造方式与基类相同. .
顺便说一句,如果你想要对可变集合进行子类化,这些都不适用于你.他们被视为scala世界中的二等公民,但他们确实有add方法,很少需要构建新的实例.以下代码:
class ListOfUsers(users: Int*) extends scala.collection.mutable.HashSet[Int] {
this ++= users
def findOdd: Option[Int] = find(_ % 2 == 1)
}
Run Code Online (Sandbox Code Playgroud)
在大多数情况下,你可能会做出或多或少的预期(map而朋友可能做不到你期望的CanBuildFrom事情,因为我会在一分钟内得到的东西,但请耐心等待我).
如果继承失败了,我们总会有一个核选择:构成.我们可以创建自己的Set子类,将其职责委托给委托,如下:
import scala.collection.SetLike
import scala.collection.mutable.Builder
import scala.collection.generic.CanBuildFrom
class UserSet(delegate: Set[Int]) extends Set[Int] with SetLike[Int, UserSet] {
override def contains(key: Int) = delegate.contains(key)
override def iterator = delegate.iterator
override def +(elem: Int) = new UserSet(delegate + elem)
override def -(elem: Int) = new UserSet(delegate - elem)
override def empty = new UserSet(Set.empty)
override def newBuilder = UserSet.newBuilder
override def foreach[U](f: Int => U) = delegate.foreach(f) // Optional
override def size = delegate.size // Optional
}
object UserSet {
def apply(users: Int*) = (newBuilder ++= users).result()
def newBuilder = new Builder[Int, UserSet] {
private var delegateBuilder = Set.newBuilder[Int]
override def +=(elem: Int) = {
delegateBuilder += elem
this
}
override def clear() = delegateBuilder.clear()
override def result() = new UserSet(delegateBuilder.result())
}
implicit object UserSetCanBuildFrom extends CanBuildFrom[UserSet, Int, UserSet] {
override def apply() = newBuilder
override def apply(from: UserSet) = newBuilder
}
}
Run Code Online (Sandbox Code Playgroud)
这可以说是太复杂而且太简单了.它的代码行数比我们写的要多得多,然而,它仍然非常天真.
它会在没有伴侣级的情况下工作,但没有CanBuildFrom,map会返回一个平原Set,这可能不是你所期望的.我们还重写了Set我们实现的文档的可选方法.
如果我们是彻底的,我们已经创建了一个CanBuildFrom,并empty为我们的可变类实现,因为这可以确保创建新实例的少数方法将按预期工作.
如果这听起来太多了,请考虑以下内容:
case class UserSet(users: Set[Int])
Run Code Online (Sandbox Code Playgroud)
当然,你必须输入几个字母来获取用户集,但我认为它比子类更好地区分了问题.
| 归档时间: |
|
| 查看次数: |
1616 次 |
| 最近记录: |