Lud*_*tey 1 scala scala-collections
我正在尝试定义一个类,该类将包含一个 Set 字段,并且希望能够直接从容器类中操作这个集合:
case class MyClass(prop: String) extends TraversableLike[Int,MyClass] {
private def mySet: Set[Int]() = Set()
override def foreach[U](f: Int => U) = data.foreach[U](f)
override def newBuilder: Builder[Int, MyClass] =
new ArrayBuffer[Int] mapResult (a => MyClass(prop, a.toSet))
implicit def canBuildFrom: CanBuildFrom[MyClass, Int, MyClass] =
new CanBuildFrom[MyClass, Int, MyClass] {
def apply(): Builder[Int, MyClass] = newBuilder
def apply(from: MyClass): Builder[Int, MyClass] = newBuilder
}
}
Run Code Online (Sandbox Code Playgroud)
我希望能够做到
var obj = MyClass("hello")
obj += 1
obj = obj map (_+1)
Run Code Online (Sandbox Code Playgroud)
第一条指令 (obj+= 1) 有效,但第二条无效。问题是我无法将隐式 canBuildFrom 放入对象 MyClass 中,因为构建器需要依赖于实例的信息(在本例中为 prop 字段)。
是否有解决方案使我的隐式可访问并保持其实例依赖性?我想避免使我的班级可变。
您的代码有几个问题:
Set[Int]()
不是 的有效类型mySet
,您应该删除()
mySet
应该是 a val
,而不是 adef
+
和 派生+=
. 如果你代表一个集合,那么它应该是一个Set
.这是修改后的尝试:
import mutable.Builder
import generic.CanBuildFrom
class MyClass private (val prop: String, private val mySet: Set[Int] = Set())
extends immutable.Set[Int] with SetLike[Int, MyClass] {
def -(elem: Int) = MyClass(prop, mySet - elem)
def +(elem: Int) = MyClass(prop, mySet + elem)
def contains(elem: Int) = mySet.contains(elem)
def iterator = mySet.iterator
override def empty: MyClass = MyClass(prop)
override def stringPrefix = "MyClass(" + prop + ")"
}
object MyClass {
def DefaultProp = "DefaultProp"
def apply(prop: String, mySet: Set[Int] = Set()) = new MyClass(prop, mySet)
def newBuilder(prop: String = DefaultProp): Builder[Int, MyClass] =
Set.newBuilder[Int] mapResult (set => MyClass(prop, set))
implicit def canBuildFrom: CanBuildFrom[MyClass, Int, MyClass] =
new CanBuildFrom[MyClass, Int, MyClass] {
def apply(): Builder[Int, MyClass] = newBuilder()
def apply(from: MyClass): Builder[Int, MyClass] = newBuilder(from.prop)
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以写:
var obj = MyClass("hello")
obj += 1
println(obj) // prints MyClass(hello)(1)
obj = obj map (_ + 1)
println(obj) // prints MyClass(hello)(2)
Run Code Online (Sandbox Code Playgroud)
让我们剖析一下:
MyClass
现在明确地是一个不可变集,在类型参数中声明了一个自定义表示SetLike
。prop
是公共 val 成员;实际集合mySet
是一个私有值。
然后我们需要实现所Set
依赖的四个操作,只需将mySet
. (这看起来可以被分解。对于Seq
s,有一个类SeqForwarder
可以完成类似的工作;不过我找不到SetForwarder
)。最后,我们提供了一个empty
方法,内置的继承构建器也依赖于该方法。最后,覆盖stringPrefix
可以使用 "MyClass" 和 的值实现更好的字符串表示prop
。
请注意,canBuildFrom
object MyClass
调用newBuilder
,尽可能传递prop
原始集合的 。这意味着大多数情况下,您可以在映射等MyClass
实例时保留此值。prop
然而,我们需要为 定义一个默认值,因为CanBuildFrom
s 必须定义一个apply
不告诉原始集合是什么的方法。(问题:为什么会发生这种情况?)
最后,我们的实现newBuilder
不再依赖于ArrayBuffer
s,而是直接构建Set
将由您的新MyClass
实例包装的实例。
更多资源: