目前正试图了解Elixir中的"^"运算符.来自网站:
当没有兴趣重新绑定变量而是匹配匹配之前的值时,可以使用pin运算符^:
来源 - http://elixir-lang.org/getting_started/4.html
考虑到这一点,您可以将新值附加到符号,如下所示:
iex> x = 1 # Outputs "1"
iex> x = 2 # Outputs "2"
Run Code Online (Sandbox Code Playgroud)
我也可以这样做:
iex> x = x + 1 # Outputs "3"!
Run Code Online (Sandbox Code Playgroud)
所以我的第一个问题是; Elixir变量是否可变? 看起来确实如此......在函数式编程语言中,这应该是不可能的?
所以现在我们来到"^"运算符......
iex> x = 1 # Outputs "1"
iex> x = 2 # Outputs "2"
iex> x = 1 # Outputs "1"
iex> ^x = 2 # "MatchError"
iex> ^x = 1 # Outputs "1"
Run Code Online (Sandbox Code Playgroud)
我认为"^"的效果是将"x"锁定到绑定到它的最后一个值.这就是它的全部吗?为什么不确保所有'匹配'/赋值都像Erlang本身一样不可变?
我刚刚习惯了......
erlang functional-programming immutability elixir variable-assignment
浏览string.GetHashCode使用Reflector的源代码会显示以下内容(对于mscorlib.dll版本4.0):
public override unsafe int GetHashCode()
{
fixed (char* str = ((char*) this))
{
char* chPtr = str;
int num = 0x15051505;
int num2 = num;
int* numPtr = (int*) chPtr;
for (int i = this.Length; i > 0; i -= 4)
{
num = (((num << 5) + num) + (num >> 0x1b)) ^ numPtr[0];
if (i <= 2)
{
break;
}
num2 = (((num2 << 5) + num2) + (num2 >> 0x1b)) ^ numPtr[1]; …Run Code Online (Sandbox Code Playgroud) 不要将可变类型的实例分配给只读字段.
使用可变类型创建的对象可以在创建后进行修改.例如,数组和大多数集合是可变类型,而Int32,Uri和String是不可变类型.对于包含可变引用类型的字段,只读修饰符可防止字段值被覆盖但不保护可变类型不被修改.
这简单地重述了readonly的行为,但没有解释为什么使用readonly是不好的.其含义似乎是许多人不理解"只读"的含义,并错误地认为只读字段是不可改变的.实际上,它建议使用"readonly"作为代码文档,指示深层不变性 - 尽管编译器无法强制执行此操作 - 并且禁止将其用于其正常功能:确保字段的值在之后不会发生变化对象已经构建.
我对使用"readonly"来表示除编译器理解的正常含义之外的其他内容感到不安.我觉得它鼓励人们误解"只读"的含义,并且期望它意味着代码作者可能不想要的东西.我觉得它排除了在可能有用的地方使用它 - 例如,表明两个可变对象之间的某些关系在其中一个对象的生命周期内保持不变.假设读者不理解"只读"的含义这一概念似乎与微软的其他建议相矛盾,例如FxCop的"不要初始化不必要"规则,该规则假定您的代码的读者是该语言的专家并且应该知道(例如)bool字段被自动初始化为false,并且阻止您提供显示"是,这已被有意识地设置为false的冗余;我不会忘记初始化它".
那么,首先,为什么Microsoft建议不要使用readonly来引用可变类型?我也有兴趣知道:
众所周知,.NET中的字符串是不可变的.(好吧,不是100%完全不可变,但设计不可变,无论如何都被任何理性的人使用.)
这使得基本上可以,例如,以下代码只在两个变量中存储对同一字符串的引用:
string x = "shark";
string y = x.Substring(0);
// Proof:
fixed (char* c = y)
{
c[4] = 'p';
}
Console.WriteLine(x);
Console.WriteLine(y);
Run Code Online (Sandbox Code Playgroud)
以上输出:
sharp
sharp
Run Code Online (Sandbox Code Playgroud)
显然,x并y指向同一个string对象.所以这是我的问题:为什么不Substring 总是与源字符串共享状态?字符串本质上是char*一个长度的指针,对吗?所以在我看来,至少在理论上应该允许分配单个内存块来保存5个字符,其中两个变量只指向该(不可变)块内的不同位置:
string x = "shark";
string y = x.Substring(1);
// Does c[0] point to the same location as x[1]?
fixed (char* c = y)
{
c[0] = 'p';
}
// Apparently not...
Console.WriteLine(x);
Console.WriteLine(y); …Run Code Online (Sandbox Code Playgroud) I am looking to do something like this (C#).
public final class ImmutableClass {
public readonly int i;
public readonly OtherImmutableClass o;
public readonly ReadOnlyCollection<OtherImmutableClass> r;
public ImmutableClass(int i, OtherImmutableClass o,
ReadOnlyCollection<OtherImmutableClass> r) : i(i), o(o), r(r) {}
}
Run Code Online (Sandbox Code Playgroud)
The potential solutions and their associated problems I've encountered are:
1. Using const for the class members, but this means the default copy assignment operator is deleted.
Solution 1:
struct OtherImmutableObject {
const int i1;
const int i2;
OtherImmutableObject(int i1, …Run Code Online (Sandbox Code Playgroud) 任何人对是否有任何意见IEquatable<T>或IComparable<T>一般应要求T是sealed(如果是class)?
这个问题发生在我身上,因为我正在编写一组旨在帮助实现不可变类的基类.基类要提供的部分功能是自动实现相等比较(使用类的字段以及可应用于字段来控制相等比较的属性).当我完成时它应该是相当不错的 - 我正在使用表达式树为每个动态创建一个编译的比较函数T,因此比较函数应该非常接近正则相等比较函数的性能.(我使用键入的不可变字典System.Type和双重检查锁定以合理的方式存储生成的比较函数)
尽管如此,有一件事是用来检查成员字段相等性的函数.我的初衷是检查每个成员字段的类型(我将调用X)是否实现IEquatable<X>.但是,经过一番思考后,除非X是这样,否则我认为这是不安全的sealed.原因在于,如果X不是sealed,我无法确定是否X正确地将等式检查委托给虚拟方法X,从而允许子类型覆盖相等比较.
这就提出了一个更普遍的问题 - 如果一个类型没有被密封,它是否应该真正实现这些接口?我想不会,因为我认为接口契约是比较两种X类型,而不是两种类型,可能是也可能不是X(虽然它们当然必须是X或者是子类型).
你们有什么感想?应该IEquatable<T>和IComparable<T>避免对开封类?(也让我想知道是否有一个fxcop规则)
我现在的想法是让我产生比较功能只能用IEquatable<T>在成员字段,其T为sealed,而是用虚拟的Object.Equals(Object obj),如果T是密封的,即使T工具IEquatable<T>,因为该领域可能的潜在店亚型T和我怀疑的大多数实现IEquatable<T>适当设计的传承.
我不知道作为一个集合的东西如何是不可变的并且仍然具有可接受的性能.
从我在F#集中读到的内部使用红黑树作为它们的实现.如果每次我们想要为Red Black Tree添加新内容,我们必须基本上重新创建它,它如何才能获得良好的性能?我在这里错过了什么?
虽然我问F#的集合,但我认为这与任何其他拥有或使用不可变数据结构的语言相关.
谢谢
Eric Lippert告诉我,我应该"尝试始终使值类型不可变",所以我认为我应该尝试始终使值类型不可变.
但是,我刚刚System.Web.Util.SimpleBitVector32在System.Web程序集中找到了这个内部可变结构,这让我觉得必须有一个很好的理由来拥有一个可变结构.我猜他们这样做的原因是因为它在测试中表现得更好,而且他们把它保持在内部以阻止它的误用.然而,这是猜测.
我已经C&P了这个结构的来源.什么是设计决定使用可变结构的合理性?一般来说,这种方法可以获得什么样的好处,什么时候这些好处足以证明潜在的损害?
[Serializable, StructLayout(LayoutKind.Sequential)]
internal struct SimpleBitVector32
{
private int data;
internal SimpleBitVector32(int data)
{
this.data = data;
}
internal int IntegerValue
{
get { return this.data; }
set { this.data = value; }
}
internal bool this[int bit]
{
get {
return ((this.data & bit) == bit);
}
set {
int data = this.data;
if (value) this.data = data | bit;
else this.data = data & ~bit;
}
}
internal int this[int …Run Code Online (Sandbox Code Playgroud) 所以我读到了HashMap.有人指出:
"Immutability还允许缓存不同键的哈希码,这使得整个检索过程非常快,并建议
IntegerJava Collection API提供的String和各种包装类(例如)是非常好的HashMap键."
我不太明白......为什么?
我从对象列表中创建了一个不可变的映射(使用Immutable-JS):
var result = [{'id': 2}, {'id': 4}];
var map = Immutable.fromJS(result);
Run Code Online (Sandbox Code Playgroud)
现在我想得到对象id = 4.
有没有比这更简单的方法:
var object = map.filter(function(obj){
return obj.get('id') === 4
}).first();
Run Code Online (Sandbox Code Playgroud) immutability ×10
.net ×4
c# ×4
performance ×2
string ×2
c++ ×1
caching ×1
const ×1
const-cast ×1
elixir ×1
erlang ×1
f# ×1
gethashcode ×1
hashcode ×1
hashmap ×1
icomparable ×1
iequatable ×1
java ×1
javascript ×1
sealed ×1
struct ×1
substring ×1