我有一个私有字段的类,它是一个可变集合。此特定实例中的字段为ArrayBuffer
,但我的问题扩展到任何有限的,有序的随机访问集合类型。我想暴露这个字段而不允许其他人修改它。在Java中,我会添加一个方法,如:
private List<T> theList;
public List<T> getList() {
return Collections.unmodifiableList(theList);
}
在Java中,我们只接受结果是List
,因为List
而朋友抛出#add
而没有完全实现UnsupportedOperationException
界面。
在Scala中,我希望找到一个适当的特征,包括iterator
,size
和apply
(用于按索引检索值)但没有变更器的访问器。这样的类型是否存在我还没有找到?
答案 0 :(得分:9)
Scala集合库面向不变性,不变性并不仅仅指您不允许修改给定集合,而且保证集合不会永远存在由任何人修改。
所以你不能并且你不应该将像immutable.Seq这样的集合作为来自Scala中可变缓冲区的视图,因为它打破了这种保证。
但你可以像这样轻松实现不可修改的可变Seq的概念:
class UnmodifiableSeq[A](buffer: mutable.Seq[A]) extends mutable.Seq[A]{
def update(idx: Int, elem: A) {throw new UnsupportedOperationException()}
def length = buffer.length
def apply(idx: Int) = buffer(idx)
def iterator = buffer.iterator
}
用法:
val xs = Array(1, 2, 3, 4)
val view = new UnmodifiableSeq(xs)
println(view(2)) >> 3
view(2) = 10 >> Exception in thread "main" java.lang.UnsupportedOperationException
编辑:
获取集合的不可修改视图的一种可能更好的方法是向下转换为collection.Seq
,它不提供可变更新操作:
val xs = Array(1, 2, 3)
val view: Seq[Int] = xs //this is unmodifiable
或创建一个包含Seq
的包装器,如果你有自己的自定义可变类。
class UnmodifiableView[A](col: MutableCollection[A]) extends collection.Seq[A]{
def length = col.length
def apply(idx: Int) = col(idx)
def iterator = col.iterator
}
scala.collection.Seq
特征不能保证不变性,但它也不允许任何修改操作,因此它看起来非常合适。
答案 1 :(得分:2)
将您的缓冲区转换为Seq,或scala.collection
包中的其他不可修改的集合之一。
myBuffer.toSeq
答案 2 :(得分:1)
如果你想:
确保无法将返回的值强制转换为可修改的值 那么一种可能性就是简单地返回一个迭代器
def getStuff = array.iterator
当然,这不是一个选项,如果您的规范明确要求您返回Seq,但它
for (x <- obj.getStuff)
)相同的语法对其进行迭代obj.getStuff.toSeq
或obj.getStuff.toList
轻松转换为Seq或列表。(注意,.iterator的文档没有明确说明返回的对象不能被强制转换为可修改的东西,但ArrayBuffer.iterator的当前实现确实提供了一个不可修改的迭代器。)
答案 3 :(得分:0)
如果myBuffer.toSeq
不够好,您可以编写自己的类,将scala.collection.IndexedSeqOptimized
委托给基础集合。