我尝试做的是提出一个 case 类,我可以在模式匹配中使用它,它只有一个字段,例如不可变的集合。此外,我想使用map,foldLeft等函数,这些函数应该传递给集合。我按照以下方式尝试了它:
case class foo(s:Set[String]) extends Iterable[String] {
override def iterator = s.iterator
}
现在,如果我尝试使用例如map函数,我得到一个类型错误:
var bar = foo(Set() + "test1" + "test2")
bar = bar.map(x => x)
found : Iterable[String]
required: foo
bar = bar.map(x => x)
^
类型错误完全正常(据我所知)。但是,我想知道如何为集合实现一个包装器案例类,以便可以调用map,foldLeft等,并仍然接收案例类的对象。是否需要覆盖所有这些功能还是有其他方法吗?
修改
我倾向于接受为我效力的RégisJean-Gilles的解决方案。然而,经过谷歌搜索几个小时后,我发现另一个有趣的Scala特征SetProxy
。我找不到任何简单的例子,所以我不确定这个特性是否符合我的要求:
Set
我的第一个想法是扩展Set
,但我的自定义类型Foo
已经扩展了另一个类。因此,第二个想法是混合特性Iterable和IterableLike。现在我对特征SetProxy
嗤之以鼻,这让我想到哪种特质是“最好的”。你有什么想法和经历?
自从我三天前开始学习Scala以来,任何指针都受到高度赞赏!
答案 0 :(得分:5)
嗯,这听起来对我很不错,但是Scala说变量b的类型是Iterable [String]而不是Foo类型,即我没有看到IterableLike在这种情况下如何帮助
你是对的。仅仅继承mpartel所示的IterableLike
将使某些方法的返回类型更加精确(例如filter
,它将返回Foo
),但是其他如map
的{{1}}您需要提供适当的flatMap
隐式。
这是一个代码片段:
CanBuildFrom
在repl中进行了一些测试:
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
}
}
答案 1 :(得分:1)
继承IterableLike[String, Foo]
为您提供所有这些方法,使它们返回Foo。除了IterableLike
之外,newBuilder
要求您实施iterator
。
import scala.collection.IterableLike
import scala.collection.mutable.{Builder, SetBuilder}
case class Foo(stuff: Set[String]) extends Iterable[String] with IterableLike[String, Foo] {
def iterator: Iterator[String] = stuff.iterator
protected[this] override def newBuilder: Builder[String, Foo] = {
new SetBuilder[String, Set[String]](Set.empty).mapResult(Foo(_))
}
}
// Test:
val a = Foo(Set("a", "b", "c"))
val b = a.map(_.toUpperCase)
println(b.toList.sorted.mkString(", ")) // Prints A, B, C