案例类作为集合的"包装器"类.那么map/foldLeft /呢

Max*_*ier 4 scala

我尝试做的是提出一个案例类,我可以在模式匹配中使用它只有一个字段,例如一个不可变集.此外,我想使用map,foldLeft等函数,这些函数应该传递给集合.我试过它,如下所示:

case class foo(s:Set[String]) extends Iterable[String] {
    override def iterator = s.iterator
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我尝试使用例如map函数,我会收到类型错误:

var bar = foo(Set() + "test1" + "test2")
bar = bar.map(x => x)

 found   : Iterable[String]
 required: foo
   bar = bar.map(x => x)
                ^
Run Code Online (Sandbox Code Playgroud)

类型错误完全正常(在我的理解中).但是,我想知道如何为集合实现一个包装器案例类,以便可以调用map,foldLeft等,并仍然接收案例类的对象.是否需要覆盖所有这些功能还是有其他方法吗?

编辑

我倾向于接受为我工作的RégisJean-Gilles的解决方案.然而,谷歌搜索了几个小时后,我发现了另一个有趣的Scala特征SetProxy.我找不到任何琐碎的例子,所以我不确定这个特性是否符合我的要求:

  1. 提出自定义类型,即不同的类型 Set
  2. 类型必须是一个case类(我们想做模式匹配)
  3. 我们需要"委托"方法map,foldLeft等,它们应该将调用传递给我们的实际集合,并返回我们新类型中生成的set wrapped arround

我的第一个想法是扩展,Set但我的自定义类型Foo已经扩展了另一个类.因此,第二个想法是混合特性Iterable和IterableLike.现在我对这个SetProxy让我思考哪种特质是"最好的"方式的特性有所了解.你有什么想法和经历?

自从我三天前开始学习Scala以来,我们非常感谢任何指针!

Rég*_*les 5

嗯这听起来对我很有意义,但Scala说变量b的类型是Iterable [String]而不是Foo类型,即我没有看到IterableLike在这种情况下如何帮助

你是对的.仅仅继承自IterableLikempartel所显示的将使某些方法的返回类型更精确(例如filter,将返回 Foo),但对于其他类似方法map,flatMap则需要提供一个适当的CanBuildFrom隐含.这是一个代码片段,它可以做到这一点:

import collection.IterableLike
import collection.generic.CanBuildFrom
import collection.mutable.Builder

case class Foo( s:Set[String] ) extends Iterable[String] with IterableLike[String, Foo] {
  override def iterator = s.iterator
  override protected[this] def newBuilder: scala.collection.mutable.Builder[String, Foo] = new Foo.FooBuilder
  def +(elem: String ): Foo = new Foo( s + elem )
}

object Foo  {
  val empty: Foo = Foo( Set.empty[String] )
  def apply( elems: String* ) = new Foo( elems.toSet )

  class FooBuilder extends Builder[String, Foo] {
    protected var elems: Foo = empty
    def +=(x: String): this.type = { elems = elems + x; this }
    def clear() { elems = empty }
    def result: Foo = elems
  }

  implicit def canBuildFrom[T]: CanBuildFrom[Foo, String, Foo] = new CanBuildFrom[Foo, String, Foo] {
    def apply(from: Foo) = apply()
    def apply() = new FooBuilder
  }
}
Run Code Online (Sandbox Code Playgroud)

在repl中进行一些测试:

scala> var bar = Foo(Set() + "test1" + "test2")
bar: Foo = (test1, test2)

scala> bar = bar.map(x => x) // compiles just fine because map now returns Foo
bar: Foo = (test1, test2)
Run Code Online (Sandbox Code Playgroud)