我听说F#本身就支持不变性,但是它不能在C#中复制呢?您从C#不可变数据中获得的F#不可变数据会得到什么?
同样在F#中,有没有办法创建可变数据?一切都是不变的吗?
如果在应用程序中同时使用C#和F#,是否可以在C#中更改不可变的F#数据?或者您是否只需要创建使用不可变F#数据的新C#类型并替换指向这些数据的引用?
我正在重新阅读Java Concurrency In Practice,我不确定我是否完全理解有关不可变性和安全发布的章节.
这本书的内容是:
任何线程都可以安全地使用不可变对象而无需额外的同步,即使不使用同步来发布它们也是如此.
我不明白的是,为什么有人(有兴趣使他的代码正确)不安全地发布一些参考?
如果对象是不可变的,并且它是不安全地发布的,我理解获得对该对象的引用的任何其他线程将看到其正确的状态,因为由适当的不变性提供的保证(使用final字段等).
但是如果发布是不安全的,那么另一个线程可能仍然会null在发布之后看到或者之前的引用,而不是对不可变对象的引用,这对我来说似乎是没有人愿意的.
如果使用安全发布来确保所有线程都能看到新引用,那么即使对象实际上是不可变的(没有final字段,但也无法将它们静音),那么一切都是安全的.正如书中所说:
安全发布的有效不可变对象可以被任何线程安全地使用而无需额外的同步.
那么,为什么不变性(与有效不变性相比)如此重要?在什么情况下需要不安全的出版物?
我目前的用例非常简单,无论是可变的还是不可变的Map都可以解决问题.
有一个采用不可变Map的方法,然后调用第三方API方法,该方法也采用不可变Map
def doFoo(foo: String = "default", params: Map[String, Any] = Map()) {
val newMap =
if(someCondition) params + ("foo" -> foo) else params
api.doSomething(newMap)
}
Run Code Online (Sandbox Code Playgroud)
有问题的地图通常很小,最多可能有一个嵌入的案例类实例列表,最多几千个条目.因此,再次假设在这种情况下对于不可变的影响很小(即通过newMap val副本基本上有2个Map实例).
不过,它让我有点唠叨,复制地图只是为了得到一张新的地图,上面贴着几个k-> v条目.
我可以params.put("bar", bar)为我想要处理的条目变为可变等等,然后params.toMap为api调用转换为immutable,这是一个选项.但后来我必须导入并传递可变映射,与使用Scala的默认不可变映射相比,这有点麻烦.
那么,对于在不可变映射上使用可变映射的合理/良好实践的一般指导原则是什么?
谢谢
编辑 所以,看起来不可变地图上的添加操作接近恒定时间,确认@ dhg和@Nicolas断言没有制作完整副本,这解决了所呈现的具体案例的问题.
说我想创建一个类car,tractor和boat.所有这些类都有一个实例,engine我想跟踪单个列表中的所有引擎.如果我正确理解电机对象是否可变,我可以将其存储为列表中的属性car以及相同的实例.
我无法找到关于用户定义的类是否可变的任何可靠信息,以及在定义它们时是否有选择可以选择,是否有人可以解释一下?
Liskov替换原则要求子类型必须满足超类型的契约.根据我的理解,这将导致ReadOnlyCollection<T>违反Liskov. ICollection<T>合同公开Add和Remove运营,但只读子类型不符合本合同.例如,
IList<object> collection = new List<object>();
collection = new System.Collections.ObjectModel.ReadOnlyCollection<object>(collection);
collection.Add(new object());
-- not supported exception
Run Code Online (Sandbox Code Playgroud)
显然需要不可变的集合.有没有关于.NET的建模方法的事情?有什么更好的方法呢? IEnumerable<T>在一个集合中做得很好,至少看起来是不可改变的.但是,语义非常不同,主要是因为IEnumerable没有明确地暴露任何状态.
在我的特定情况下,我正在尝试构建一个不可变的DAG类来支持FSM.我显然在开始时需要AddNode/ AddEdge方法,但我不希望它一旦运行就可以更改状态机.我很难表示DAG的不可变和可变表示之间的相似性.
现在,我的设计涉及预先使用DAG Builder,然后创建一次不可变图,此时它不再可编辑.Builder和具体的不可变DAG之间唯一的通用接口是Accept(IVisitor visitor).我担心,面对可能更简单的选择,这可能是过度设计/过于抽象.与此同时,我无法接受我可以在我的图形界面上公开可能NotSupportedException在客户端获得特定实现时抛出的方法.处理这个问题的正确方法是什么?
c# liskov-substitution-principle immutability readonly-collection directed-acyclic-graphs
我已经使用有状态存储以"正常"方式构建了我的第一个React应用程序,现在我正在研究使用Este starterkit中使用的不可变全局状态.
它以几种方式简化了应用程序结构:
我只读了关于在React中使用不可变数据的积极的事情,建议避免组件中的状态,所以我想知道是否有任何缺点.我想一定有,因为否则我不明白为什么它不推荐,因为在构建应用程序做出反应的方式.
不变性对我来说是新的,所以如果我在一个复杂的真实应用程序中开始使用这种方法,我应该注意一些警告吗?
我能想到的唯一一件小事是在Este使用它时使用forceUpdate(),因为我已经读过它是一个同步函数.例如,Morearty似乎将更新推迟到下一个动画帧以便批量处理它们,但我认为这是一个实现细节/优化,而不是一些继承的不可变单态方法的缺点.
为什么std::io::copy需要将reader和writer参数作为可变引用传递?
我可以理解为什么编写器需要进行变异才能容纳写入数据的数据,从而改变其内部状态.
但是,为什么读者也必须被标记为可变参考?如果我只是在读数据,那么我不是只需要对给定类型的引用而不是可变引用吗?
是否可以在Golang中定义不可变的结构?初始化后,只对struct的字段进行读操作,不修改字段值.如果是这样,该怎么做.
有几次,我遇到了可变和不可变引用都需要访问器方法的场景.
对于~3行,复制逻辑不是问题,但是当逻辑变得更复杂时,复制粘贴大块代码并不好.
我希望能够重新使用这两个代码.
Rust是否提供了一些方法来处理这个更好的复制粘贴代码或使用unsafe强制转换?
例如:
impl MyStruct {
pub fn get_foo(&self) -> &Bar {
// ~20 lines of code
// --- snip ---
return bar;
}
pub fn get_foo_mut(&mut self) -> &mut Bar {
// ~20 lines of code
// (exactly matching previous code except `bar` is mutable)
// --- snip ---
return bar;
}
}
Run Code Online (Sandbox Code Playgroud)
下面是一个代码库的更详细的摘录,其中一个不可变的返回参数被强制转换为可变的,以支持函数的不可变和可变版本.它使用包装指针类型(ConstP以及MutP用于不可变和可变引用),但函数的逻辑应该是清楚的.
pub fn face_vert_share_loop<V, F>(f: F, v: V) -> LoopConstP
where V: Into<VertConstP>,
F: Into<FaceConstP>
{
into_expand!(f, v); …Run Code Online (Sandbox Code Playgroud) immutability ×10
c# ×3
mutable ×2
rust ×2
class ×1
f# ×1
go ×1
immutable.js ×1
java ×1
javascript ×1
liskov-substitution-principle ×1
map ×1
python ×1
reactjs ×1
reference ×1
scala ×1
traits ×1
types ×1
use-case ×1