有人可以解释为什么带有整数的示例会导致x和y的值不同,而列表中的示例会导致x和y成为同一个对象吗?
x = 42
y = x
x = x + 1
print x # 43
print y # 42
x = [ 1, 2, 3 ]
y = x
x[0] = 4
print x # [4, 2, 3]
print y # [4, 2, 3]
x is y # True
Run Code Online (Sandbox Code Playgroud) 我清楚地记得从早期的.NET开始,在StringBuilder上调用ToString用于提供新的字符串对象(要返回)与StringBuilder使用的内部char缓冲区.这样,如果使用StringBuilder构造了一个巨大的字符串,则调用ToString不必复制它.
在这样做时,StringBuilder必须阻止对缓冲区的任何其他更改,因为它现在由不可变字符串使用.因此,StringBuilder将切换到"复制更改",其中任何尝试的更改将首先创建新缓冲区,将旧缓冲区的内容复制到它,然后才更改它.
我认为假设StringBuilder将用于构造一个字符串,然后转换为常规字符串并丢弃.对我来说似乎是一个合理的假设.
现在就是这个.我在文档中找不到任何提及.但我不确定它是否有记录.
所以我使用Reflector(.NET 4.0)查看了ToString的实现,在我看来它实际上是复制字符串,而不是仅仅共享缓冲区:
[SecuritySafeCritical]
public override unsafe string ToString()
{
string str = string.FastAllocateString(this.Length);
StringBuilder chunkPrevious = this;
fixed (char* str2 = ((char*) str))
{
char* chPtr = str2;
do
{
if (chunkPrevious.m_ChunkLength > 0)
{
char[] chunkChars = chunkPrevious.m_ChunkChars;
int chunkOffset = chunkPrevious.m_ChunkOffset;
int chunkLength = chunkPrevious.m_ChunkLength;
if ((((ulong) (chunkLength + chunkOffset)) > str.Length) || (chunkLength > chunkChars.Length))
{
throw new ArgumentOutOfRangeException("chunkLength", Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
fixed (char* chRef = chunkChars)
{
string.wstrcpy(chPtr + chunkOffset, chRef, chunkLength);
} …Run Code Online (Sandbox Code Playgroud) 你能告诉我什么是可变位图吗?可变位图和不可变位图有哪些优点/缺点或限制.谢谢
好吧,据我所知,不可变类型本质上是线程安全的,所以我在不同的地方读过,我想我明白为什么会这样.如果在创建对象后无法修改实例的内部状态,则对实例本身的并发访问似乎没有问题.
因此,我可以创建以下内容List:
class ImmutableList<T>: IEnumerable<T>
{
readonly List<T> innerList;
public ImmutableList(IEnumerable<T> collection)
{
this.innerList = new List<T>(collection);
}
public ImmutableList()
{
this.innerList = new List<T>();
}
public ImmutableList<T> Add(T item)
{
var list = new ImmutableList<T>(this.innerList);
list.innerList.Add(item);
return list;
}
public ImmutableList<T> Remove(T item)
{
var list = new ImmutableList<T>(this.innerList);
list.innerList.Remove(item);
return list;
} //and so on with relevant List methods...
public T this[int index]
{
get
{
return this.innerList[index];
}
}
public IEnumerator<T> GetEnumerator()
{ …Run Code Online (Sandbox Code Playgroud) 我知道正常的可变映射是如何工作的(使用哈希表),我知道不可变列表是如何工作的(递归链表)和它们相对于可变列表的优势(恒定时间附加而不会弄乱原始数据)但是不可变映射(例如Scala)如何工作?
我知道在生成新映射时不会弄乱原始映射的优势,但是底层数据结构如何工作,以及它们具有哪种性能特征,例如与可变哈希表相比?是否有人们用来实现这些的标准数据结构,我可以在CLRS /维基百科中查找?
在Java中,字符串是不可变的.如果我们有一个字符串并对其进行更改,我们将获得由同一个变量引用的新字符串:
String str = "abc";
str += "def"; // now str refers to another piece in the heap containing "abcdef"
// while "abc" is still somewhere in the heap until taken by GC
Run Code Online (Sandbox Code Playgroud)
据说 int和double在C#中是不可变的.这是否意味着当我们有int并稍后更改它时,我们会得到同一个变量"指向"的新int?同样的事情,但堆栈.
int i = 1;
i += 1; // same thing: in the stack there is value 2 to which variable
// i is attached, and somewhere in the stack there is value 1
Run Code Online (Sandbox Code Playgroud)
那是对的吗?如果没有,int以什么方式不可变?
我希望我的类有一个可以分配不可变数组的存储属性.如果我这样做:
class MyClass{
var myItems:[String]
}
Run Code Online (Sandbox Code Playgroud)
我可以为我的属性分配不同的数组,但数组将是可变的.如果我这样做:
class MyClass{
let myItems:[String]
}
Run Code Online (Sandbox Code Playgroud)
我的数组是不可变的,但我不能改变分配给它的内容.有没有办法让我的蛋糕也不会改变它?
我提出的最好的方法是在数组周围创建一个包装器,然后使用该类型作为属性,如下所示:
class MyClass{
struct ImmutableWrapper{
let array:[String]
}
var myItems:ImmutableWrapper
}
Run Code Online (Sandbox Code Playgroud)
......这不是很优雅.
假设我使用Immutable.js定义了以下记录:
var Address = Immutable.Record({street: '', city: '', zip: ''});
var User = Immutable.Record({name: '', address: new Address()});
Run Code Online (Sandbox Code Playgroud)
如何将普通的javascript对象转换为用户记录?我尝试了以下但它不会产生预期的输出:
var user = new User({name: 'Foo', address: {street: 'Bar', city: 'Baz'}});
// => Record { "name": "Foo", "address": [object Object] }
Run Code Online (Sandbox Code Playgroud)
我知道可以显式创建地址记录:
var user = new User({name: 'Foo', address: new Address({street: 'Bar', city: 'Baz'})});
// => Record { "name": "Foo", "address": Record { "street": "Bar", "city": "Baz", "zip": "" } }
Run Code Online (Sandbox Code Playgroud)
但这不是我想要的解决方案.想象一下,你有记录嵌套了几个级别,并希望将数据存储/检索为JSON(例如在数据库中).我想使用实际的用户记录结构作为重新创建嵌套记录的模式信息.或者有更好的方法来表示嵌套和结构化的不可变数据吗?
首先,让代码说:
#[derive(Debug)]
struct Bar;
#[derive(Debug)]
struct Qux {
baz: bool
}
#[derive(Debug)]
struct Foo {
bars: Vec<Bar>,
qux: Qux,
}
impl Foo {
fn get_qux(&mut self) -> &mut Qux {
&mut self.qux
}
fn run(&mut self) {
// 1. Fails:
let mut qux = self.get_qux();
// 2. Works:
// let mut qux = &mut Qux { baz: false };
// 3. Works:
// let mut qux = &mut self.qux;
let qux_mut = &mut qux;
qux_mut.baz = true;
for bar in …Run Code Online (Sandbox Code Playgroud) 我无法在stackoverflow和Julia文档中找到以下"设计问题"的答案:
假设我想定义以下对象
struct Person
birthplace::String
age::Int
end
Run Code Online (Sandbox Code Playgroud)
既然Person是不可改变的,我很高兴没有人可以改变birthplace任何Person创造的,但是,这也意味着当时间过去,我无法改变他们的age......
另一方面,如果我将类型定义Person为
mutable struct Person
birthplace::String
age::Int
end
Run Code Online (Sandbox Code Playgroud)
我现在可以制作它们age,但我没有以前的安全性birthplace,任何人都可以访问并更改它.
到目前为止我找到的解决方法如下
struct Person
birthplace::String
age::Vector{Int}
end
Run Code Online (Sandbox Code Playgroud)
显然age是1元素Vector.
我发现这个解决方案非常难看并且绝对不是最理想的,因为每次都必须使用方括号访问年龄.
是否还有其他更优雅的方法在对象中包含不可变字段和可变字段?
也许问题是我错过了在一个内容中具有可变性或不可变性的真正价值struct.如果是这样的话,你能解释一下吗?
immutability ×10
c# ×2
mutable ×2
.net ×1
android ×1
arrays ×1
bitmap ×1
immutable.js ×1
int ×1
javascript ×1
julia ×1
mutability ×1
python ×1
rust ×1
scala ×1
struct ×1
swift ×1
tostring ×1