在水星我可以使用:
A = B^some_field := SomeValue
Run Code Online (Sandbox Code Playgroud)
至A与B结合的副本,除了some_field是SomeValue不是不管它是B.我相信哈斯克尔相当于是一样的东西:
a = b { some_field = some_value }
Run Code Online (Sandbox Code Playgroud)
Scala是否有类似的东西用于"修改"不可变值.替代方案似乎是有一个构造函数直接设置实例中的每个字段,这并不总是理想的(如果构造函数应该保持不变).如果我必须明确地传递我想要修改副本的实例中的所有其他值,那么它会非常笨重而且更加脆弱.
我通过谷歌搜索,或者在语言参考手册或"Scala By Example"(我已经阅读了从头到尾,但尚未全部吸收,所以它可能好吧在那里).
我可以看到这个功能可能与Java风格的访问保护和子类有一些奇怪的交互,虽然......
在为金融服务行业构建大型多线程应用程序时,我尽可能地使用不可变类和工作流模型.我对结果非常满意.它使用了相当数量的堆空间(在Java btw中),但JVM的GC在短期不可变类中运行良好.
我只是想知道今后使用这种模式是否有任何缺点?在调试团队配对代码时,我经常发现自己以这种或那种方式推荐这种模式.我猜一旦有人拿锤子,一切看起来像钉子.所以问题是:这种设计模式(范式?)什么时候会运作不佳?
我的预感是当内存使用是一个大问题,或者当项目限制需要一些低级C的东西时,等等.
拿这两个Java类:
class User {
final Inventory inventory;
User (Inventory inv) {
inventory = inv;
}
}
class Inventory {
final User owner;
Inventory (User own) {
owner = own;
}
}
Run Code Online (Sandbox Code Playgroud)
有没有办法没有使用反射*来解决这个问题?我实际上并不指望它是,但它可以不会受到质疑.
更新:因为在字节码构造中有两个步骤(1.分配对象,2.调用构造函数**)这可能是(ab)用来做手写字节码或自定义编译器吗?我正在谈论首先对两个对象执行步骤1,然后使用步骤1中的参考执行步骤2.当然,类似的东西会相当麻烦,这部分问题是学术性的.
(*因为反射可能会给安全管理员带来麻烦)
(**说我的知识有限)
我试图确定ImmutableList的最佳实践.以下是一个简单的例子,有助于解决我的问题:
例如:
public ImmutableCollection<Foo> getFooOne(ImmutableList<Foo> fooInput){
//.. do some work
ImmutableList<Foo> fooOther = // something generated during the code
return fooOther;
}
public Collection<Foo> getFooTwo(List<Foo> fooInput){
//.. do some work
List<Foo> fooOther = // something generated during the code
return ImmutableList.copyOf(fooOther);
}
public void doSomethingOne(){
ImmutableCollection<Foo> myFoo = getFooOne(myList);
...
someOtherMethod(myFoo);
}
public void doSomethingTwo(){
Collection<Foo> myFoo = getFooOne(myList);
...
someOtherMethod(myFoo);
}
Run Code Online (Sandbox Code Playgroud)
我的问题:
哪个在应用程序中最有意义?[doSomethingOne和getFooOne]或[doSomethingTwo和fooTwo]?换句话说,如果你知道你正在使用ImmutableCollections,那么继续来回和执行copyOf(),或者只是在各地使用Immutable是有意义的吗?
这些示例是公共方法,可能意味着其他人使用它们.如果这些方法是私有的并且在内部使用,那么这些答案会改变吗?
如果用户尝试向不可变List添加任何内容,则将抛出异常.因为他们可能没有意识到这一点,显然返回一个ImmutableCollection而不是Collection会更有意义吗?
简短版本:作为无序项目字典实现的多集合的最佳散列算法是什么?
我正在尝试将一个不可变的multiset(这是一个包或其他语言的多重集合:像一个数学集,除了它可以容纳多个元素)作为字典实现.我已经创建了标准库类的子类collections.Counter,类似于这里的建议:Python hashable dicts,它建议像这样的哈希函数:
class FrozenCounter(collections.Counter):
# ...
def __hash__(self):
return hash(tuple(sorted(self.items())))
Run Code Online (Sandbox Code Playgroud)
创建完整的项目元组会占用大量内存(相对于使用生成器而言),并且哈希将在我的应用程序的内存密集型部分中发生.更重要的是,我的字典键(multiset元素)可能不会是可订购的.
我正在考虑使用这个算法:
def __hash__(self):
return functools.reduce(lambda a, b: a ^ b, self.items(), 0)
Run Code Online (Sandbox Code Playgroud)
我想使用按位XOR意味着顺序与散列值无关,与元组的散列不同?我想我可以在我的数据的无序流序列上半实现Python元组散列算法.请参阅https://github.com/jonashaag/cpython/blob/master/Include/tupleobject.h(在页面中搜索"hash"一词) - 但我几乎不知道有足够的C来阅读它.
思考?建议?谢谢.
set(),但事情必须是哈希的.)
@marcin和@senderle都给出了相同的答案:使用hash(frozenset(self.items())).这是有道理的,因为items()"视图"是设置的.@marcin是第一个,但我给@senderle打了一个复选标记,因为对不同解决方案的大O运行时间进行了很好的研究.@marcin还提醒我要包含一个__eq__方法 - 但是继承自的方法dict会很好用.这就是我实现所有内容的方式 - 欢迎基于此代码的进一步意见和建议:
class FrozenCounter(collections.Counter):
# Edit: A previous version of this code included a __slots__ definition.
# But, from the Python documentation: "When …Run Code Online (Sandbox Code Playgroud) 为什么不声明一个数组最终使它在Java中不可变?不宣称最终意味着它无法改变?
从与不可变数组相关的问题中可以清楚地看出,声明一个数组final并不会使它不可更改.
以下是可能的.
final int[] array = new int[] {0, 1, 2, 3};
array[0] = 42;
Run Code Online (Sandbox Code Playgroud)
我的问题是:那么在这里宣布决赛的功能是什么?
刚刚发现以下声明作为利益 immutable object
不可变对象总是具有"失败原子性"(Joshua Bloch使用的术语):如果不可变对象抛出异常,它永远不会处于不合需要或不确定状态.
任何人都可以更详细地解释它,为什么会这样呢?
即使集合不可用,会员检查其他集合工作:
>>> set() in {frozenset()}
True
Run Code Online (Sandbox Code Playgroud)
我期望TypeError: unhashable type: 'set',与Python中的其他行为一致:
>>> set() in {} # doesn't work when checking in dict
TypeError: unhashable type: 'set'
>>> {} in {frozenset()} # looking up some other unhashable type doesn't work
TypeError: unhashable type: 'dict'
Run Code Online (Sandbox Code Playgroud)
那么,如何在其他集合中设置成员身份?
我理解注释是不可变的,但是,Java中的数组本身并不是不可变的.运行测试后,我注意到从注释参数返回的数组可以变异,但它不会影响源数组:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface ArrayAnnotation {
String[] value() default {};
}
@ArrayAnnotation({"foo"})
public class Main {
public static void main(String[] args) {
ArrayAnnotation test = Main.class.getAnnotation(ArrayAnnotation.class);
String[] test0 = test.value();
test0[0] = "bar";
System.out.println(test0[0]);
String[] test1 = test.value();
System.out.println(test1[0]);
}
}
Run Code Online (Sandbox Code Playgroud)
这打印:
bar
foo
Run Code Online (Sandbox Code Playgroud)
幕后发生了什么事?在每次调用期间是否只发生了一个数组副本value(),或者它是否更复杂?
我不确定我是否完全理解下面的小片段(在 Py v3.6.7 上)中发生的事情。如果有人能向我解释我们如何成功地改变列表,即使 Python 抛出了一个错误,那就太好了。
我知道我们可以改变一个列表并更新它,但是错误是什么?就像我的印象是,如果有错误,那么x应该保持不变。
x = ([1, 2], )
x[0] += [3,4] # ------ (1)
Run Code Online (Sandbox Code Playgroud)
第 (1) 行抛出的 Traceback 是
> TypeError: 'tuple' object doesn't support item assignment..
Run Code Online (Sandbox Code Playgroud)
我明白错误意味着什么,但我无法获得它的上下文。
但是现在如果我尝试打印变量的值x,Python 会说它是,
> TypeError: 'tuple' object doesn't support item assignment..
Run Code Online (Sandbox Code Playgroud)
据我所知,异常发生在 Python 允许列表的突变发生之后,然后希望它尝试重新分配它。我认为它吹到了那里,因为元组是不可变的。
有人可以解释一下引擎盖下发生了什么吗?
编辑 - 1 错误来自 ipython 控制台作为图像;
immutability ×10
java ×5
python ×3
final ×2
hash ×2
scala ×2
akka ×1
annotations ×1
arrays ×1
atomicity ×1
dictionary ×1
guava ×1
object ×1
python-3.2 ×1
python-3.x ×1
reflection ×1
set ×1
tuples ×1