像是js,以及c#等一系列的语言,推出任何一个特征都要和c比一比,你知道的:)。
string的不可变性也是一样,你看:
C的string是可以改变的。
你可以
char str[] = "Foo";
str[0] = ‘G'
str的内容确实被改变了。可以通过print来证明。打印内容,也打印指针。指针不变,内容变了。
2.js的不可改.如下的代码,没有任何效果,也可以log出来证明
var str = "foo";
str[0] = 'g' ;
因为,语义上来说,这样做意味着原位修改str的内存区内容
但是你可以
var str = "foo";
var = 'bar'
因为原位置的内存没有修改,是新分配的。只是打印不了指针,不好直接证明。要么就看代码,那就啰嗦了。非常非常的啰嗦。
不少语言对字符串的实现,都采用了限定不变性。不能说这是不费解的:为何去创建一个新字符串,而不是去修改它呢?毕竟c就是这样做的。
字符串的不可变性有不少好处,但是如果程序员忘了这一点也会导致问题。
如下的c#代码会创建10000个字符串对象,但是除了最后一个,后面都是垃圾需要被回收的。
string s = string.Empty;
for (int i = 0; i < 10000; i++)
{
s += "x";
}
通过cld profiler可以看到这张图。
这样的场景应该使用StringBuilder。而不是字符串连接。
StringBuilder sb = StringBuilder();
for( i = ; i < 10000; i++)
{
sb.Append();
}
string x = sb.ToString();
针对js,也可以自己做一个StringBuilder
function StringBuilder() {
this._array = [];
this._index = 0;
}
StringBuilder.prototype.append = function (str) {
this._array[this._index] = str;
this._index++;
}
StringBuilder.prototype.toString = function () {
return this._array.join('');
}
为何设计者决定实现不可变字符串呢?
这个和存储优化有关。字符串都存储在俘虏池(intern pool)内,因为string都在intern pool内,所以,相同的字符串引用一致。这样的存储效果很好。
可是,如果允许修改string,那么a修改了,b也会跟着修改,d也是。可是,语义上来说,我们认为他们是不同的变量,不应该联动。所以字符串不可变就是intern pool存储的代价。
string a = "xx";
string b = "xx";
string c = "x";
string d = String.Intern(c + c);
Console.WriteLine((object)a == (object)b); Console.WriteLine((object)a == (object)d);
String的intern()方法就是扩充常量池的一个方法;当一个String实例str调用intern()方法时,c# 查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其的引用,如果没有,则在常量池中增加一个Unicode等于str的字符串并返回它的引用;
不变性,对多线程应用是有好处的。
另一个场景是字符串可以用于哈希表的键,而键是不可以改变值的。
string key = "abc";
Hashtable ht = new Hashtable();
ht.Add(key, 123);
key = "xbc";
Console.WriteLine(key); // xbc
Console.WriteLine(ht["abc"]); // 123
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。