加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

扩展Scala集合的简单示例

发布时间:2020-12-16 09:25:14 所属栏目:安全 来源:网络整理
导读:我正在寻找一个非常简单的子类化Scala集合的例子.我对这一切是如何以及为何有效的全面解释并不感兴趣;在互联网上有很多可用的 here和 elsewhere.我想知道这样做的简单方法. 下面的类可能是一个尽可能简单的例子.这个想法是,创建一个Set [Int]的子类,它有一个
我正在寻找一个非常简单的子类化Scala集合的例子.我对这一切是如何以及为何有效的全面解释并不感兴趣;在互联网上有很多可用的 here和 elsewhere.我想知道这样做的简单方法.

下面的类可能是一个尽可能简单的例子.这个想法是,创建一个Set [Int]的子类,它有一个额外的方法:

class SlightlyCustomizedSet extends Set[Int] {
  def findOdd: Option[Int] = find(_ % 2 == 1)
}

显然这是错误的.一个问题是没有构造函数将东西放入Set中.必须构建CanBuildFrom对象,最好通过调用一些已知的库代码来知道如何构建它.我已经看到在配对对象中实现几个附加方法的示例,但它们显示了它是如何工作的或如何做更复杂的事情.我想看看如何利用库中已有的东西来解决这几行代码问题.实现这一目标的最简单,最简单的方法是什么?

解决方法

如果您只想将一个方法添加到类中,那么子类化可能不是最佳选择. Scala的集合库有点复杂,并且叶子类并不总是适合子类化(可以从子类化HashSet开始,但这会让你开始深入兔子洞的旅程).

也许实现目标的更简单方法是:

implicit class SetPimper(val s: Set[Int]) extends AnyVal {
  def findOdd: Option[Int] = s.find(_ % 2 == 1)
}

这实际上并不是Set的子类,而是创建一个隐式转换,允许您执行以下操作:

Set(1,2,3).findOdd // Some(1)

沿着兔子洞

如果你来自Java背景,那么扩展标准集合可能会非常令人惊讶 – 毕竟Java标准库充满了j.u.ArrayList子类,几乎任何可以包含其他东西的东西.但是,Scala有一个关键的区别:它的首选集合都是不可变的.

这意味着他们没有添加可以就地修改它们的方法.相反,它们具有构造新实例的方法,包括所有原始项目以及新项目.如果他们天真地实现这一点,那就非常低效,因此他们使用各种特定于类的技巧来允许新实例与原始实例共享数据.该方法甚至可以返回与原始对象不同的对象 – 一些集合类对小集合或空集合使用不同的表示.

但是,这也意味着如果你想要继承其中一个不可变集合,那么你需要理解你正在子类化的类的内容,以确保你的子类实例的构造方式与基类相同. .

顺便说一句,如果你想要对可变集合进行子类化,那么这些都不适用于你.他们被视为scala世界中的二等公民,但他们确实有添加方法,很少需要构建新实例.以下代码:

class ListOfUsers(users: Int*) extends scala.collection.mutable.HashSet[Int] {
  this ++= users

  def findOdd: Option[Int] = find(_ % 2 == 1)
}

在大多数情况下,你可能会或多或少地做出你期望的事情(地图和朋友可能做不到你期望的事情,因为我会在一分钟之内找到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
    }
}

这可以说是太复杂而且太简单了.它的代码行数远远超过我们编写的代码,但它仍然非常天真.

它将在没有伴侣类的情况下工作,但如果没有CanBuildFrom,map将返回一个普通的Set,这可能不是您所期望的.我们还重写了我们实现的Set文档的可选方法.

如果我们是彻底的,我们已经创建了一个CanBuildFrom,并为我们的可变类实现了空,因为这可以确保创建新实例的少数几个方法将按预期工作.

但这听起来像是很多工作……

如果这听起来太多了,请考虑以下内容:

case class UserSet(users: Set[Int])

当然,你必须输入几个字母来获取用户集,但我认为它比子类更好地区分问题.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读