我知道适用于一般不可变类的通常原因,即
但是,包装类表示基本类型,基本类型是可变的.那么为什么封装类不可变?
我有一个类,它将ByteBuffer作为构造函数参数.有没有办法避免制作防御性副本,以确保缓冲区不会在该点之后被修改?
ByteBuffer.isReadOnly()不保证原始所有者不会修改缓冲区.更糟糕的是,似乎没有办法将ByteBuffer子类化.有任何想法吗?
我正在学习斯卡拉,作为一名优秀的学生,我试图遵守我发现的所有规则.
一条规则是:不可靠性!
所以我试图使用不可变数据结构和val来编写所有代码,有时候这很难.
但今天我想到了自己:唯一重要的是对象/类应该没有可变状态.我不是被迫以不可变的样式编写所有方法,因为这些方法不会相互影响.
我的问题:我是否正确或有任何问题/缺点我看不到?
编辑:
aishwarya的代码示例:
def logLikelihood(seq: Iterator[T]): Double = {
val sequence = seq.toList
val stateSequence = (0 to order).toList.padTo(sequence.length,order)
val seqPos = sequence.zipWithIndex
def probOfSymbAtPos(symb: T, pos: Int) : Double = {
val state = states(stateSequence(pos))
M.log(state( seqPos.map( _._1 ).slice(0, pos).takeRight(order), symb))
}
val probs = seqPos.map( i => probOfSymbAtPos(i._1,i._2) )
probs.sum
}
Run Code Online (Sandbox Code Playgroud)
说明:这是一种计算变量阶齐次马尔可夫模型的对数似然的方法.state的apply方法获取所有先前的符号和即将到来的符号,并返回这样做的概率.
正如您所看到的:整个方法只是增加了一些使用变量更容易的概率.
我希望能够根据具体类可能具有的各种属性从特征组装域对象.当我的对象是可变的时,这非常简单.例如:
trait HasHitPoints { var hitPoints: Int = 100 }
trait HasBearing { var bearing: Double = 0 }
class Ship extends HasHitPoints with HasBearing
class Base extends HasHitPoints
val entities = new Ship :: new Base :: Nil
entities.collect { case h: HasHitPoints => h.hitPoints += 10 }
Run Code Online (Sandbox Code Playgroud)
特别是,我可以在HasHitPoints不知道具体类型的情况下以多态方式读取或更新任何实例.
使用不可变对象实现此操作的最佳方法是什么?如果我很高兴只阅读属性,那么我可以做类似的事情:
trait HasHitPoints { val hitPoints: Int }
trait HasBearing { val bearing: Double }
case class Ship(hitPoints: Int, bearing: Double) extends HasHitPoints with HasBearing
case class Base(hitPoints: …Run Code Online (Sandbox Code Playgroud) 我目前正在尝试将更多功能的编程风格应用于涉及低级(基于LWJGL)的GUI开发的项目.显然,在这种情况下,需要携带很多状态,这在当前版本中是可变的.我的目标是最终拥有一个完全不可变的状态,以避免状态变化作为副作用.我研究了scalaz的镜头和状态monad一段时间,但我主要担心的是:所有这些技术都依赖于写时复制.由于我的州有大量的田地和一些相当大的田地,我担心表现.
据我所知,修改不可变对象的最常用方法是使用生成的copy方法case class(这也是镜头所做的内容).我的第一个问题是,这种copy方法是如何实际实现的?我用以下类进行了一些实验:
case class State(
innocentField: Int,
largeMap: Map[Int, Int],
largeArray: Array[Int]
)
Run Code Online (Sandbox Code Playgroud)
标杆管理,并通过查看输出-Xprof,它看起来像更新someState.copy(innocentField = 42)实际进行深拷贝和我观察显著性能下降,当我增加的大小largeMap和largeArray.我某种程度上期望新构造的实例共享原始状态的对象引用,因为内部引用应该只传递给构造函数.我可以以某种方式强制或禁用默认的这种深度复制行为copy吗?
在思考写时复制问题时,我想知道FP中是否存在更多通用的解决方案,它以一种增量方式存储不可变数据的变化(在"收集更新"或"收集"的意义上)变化").令我惊讶的是我找不到任何东西,所以我尝试了以下方法:
// example state with just two fields
trait State {
def getName: String
def getX: Int
def setName(updated: String): State = new CachedState(this) {
override def getName: String = updated
}
def setX(updated: Int): State = new CachedState(this) {
override def getX: Int = updated
} …Run Code Online (Sandbox Code Playgroud) state design-patterns functional-programming scala immutability
如果我打电话toSeq给一个不可变的Set集合,我会得到一个ArrayBuffer.
scala> Set(1,2,3).toSeq // returns Seq[Int] = ArrayBuffer(1, 2, 3)
Run Code Online (Sandbox Code Playgroud)
这让我感到惊讶.鉴于Scala强调使用不可变数据结构,我期望得到一个不可变的序列,如a Vector或List代替mutable ArrayBuffer.set元素的返回顺序当然应该是未定义的,但似乎没有任何语义上的原因,为什么这个顺序也应该是可变的.
一般来说,我希望Scala操作总是产生不可变的结果,除非我明确请求一个可变的结果.这一直是我的假设,但这里是一个不正确的,我实际上只花了一个小时调试一个问题,其中一个意外的存在ArrayBuffer导致一个match语句中的运行时错误.我的修复是改变Set(...).toSeq到Set(...).toList,但这种感觉就像一个黑客,因为有我的应用程序没有什么需要在这一点上特别的列表.
Set(...).toSeq在Scala的实现中返回一个可变对象是一个缺陷,还是有一个我在这里误解的原则?
这是Scala 2.9.2.
我很清楚在我的应用程序中使用不可变数据的好处,我对在简单的同步编程环境中使用这些不可变结构的想法非常满意.
Stack Overflow上有一个很好的例子,描述了通过在一系列递归调用中传递状态来管理游戏的状态,如下所示:
function update(state) {
sleep(100)
return update({
ticks: state.ticks + 1,
player: player
})
}
Run Code Online (Sandbox Code Playgroud)
我们可以在函数体中做一些任意的,无副作用的自由工作,然后我们返回一个新状态,而不是改变旧状态.
将它转换为简单的异步模型似乎相当容易,比如说Javascript.
function update(state) {
const newState = {
player,
ticks: state.ticks + 1
};
setTimeout(update.bind(this, newState), 100);
}
Run Code Online (Sandbox Code Playgroud)
但是,只要我们有更多的异步事件源,管理保持状态不可变和函数纯净似乎变得更加困难.
如果我们在示例中添加click事件,我们最终得到的代码如下所示.
window.addEventListener('click', function() {
// I have no idea what the state is
// because only our update loop knows about it
});
Run Code Online (Sandbox Code Playgroud)
显然,我不想在这个方法中改变状态,但我需要访问状态才能创建一个新的状态,就像这样.
window.addEventListener('click', function() {
const state = getState();
createState({
player,
clicks: clicks + 1
});
});
Run Code Online (Sandbox Code Playgroud)
但似乎这需要某种可变的状态管理器?
或者,我想我可以将click事件添加到要在更新循环中处理的操作队列,例如:
window.addEventListener('click', function() …Run Code Online (Sandbox Code Playgroud) 我有一个Employees像这样调用的不可变类:
public final class Employees {
private final List<Person> persons;
public Employees() {
persons = new LinkedList<Person>();
}
public List<Person> getPersons() {
return persons;
}
}
Run Code Online (Sandbox Code Playgroud)
如何让这个类保持不变?
我做了现场private,并final和我没有提供setter方法.这足以实现不变性吗?
为什么ints和doubles不可变?每次要更改值时返回新对象的目的是什么?
我问的原因是因为我正在创建一个类:BoundedInt它有一个值和一个上限和下限.所以我想知道:我是否应该使这种类型不变?(或者它应该是struct?)
immutability ×10
scala ×4
java ×3
asynchronous ×1
c# ×1
class ×1
const ×1
d ×1
field ×1
inheritance ×1
javascript ×1
mutable ×1
nio ×1
sequence ×1
set ×1
state ×1
types ×1