【问题标题】:If variables in Elixir are immutable why can you append to tuples and lists?如果 Elixir 中的变量是不可变的,为什么你可以附加到元组和列表中?
【发布时间】:2019-08-30 03:28:51
【问题描述】:

在下面的示例中,我创建了一个列表,然后在该列表中添加了一个新值。如果 Elixir 完全是关于不变性的,这怎么可能呢?

l = [1,2,3,4]
  iex> [1,2,3,4]
l = l ++ [5]
  iex> [1,2,3,4,5]

如果我没记错的话,这是将列表重新分配给同一个列表,这应该是不可能的,当我再次调用 l 时,它应该打印出 1 到 4 而不是 1 到 5。我不明白什么?

【问题讨论】:

    标签: elixir


    【解决方案1】:

    当您为变量分配新值时,实际上是创建了一个具有相同名称的新变量

    首先,当您执行l ++ [5] 时,没有任何内容附加到l,因为它是不可变的。而是创建一个包含l 和新元素的新列表

    现在当您执行l = l ++ [5] 时,您也不会真正附加到变量l,您只需删除前一个l 变量并创建一个新变量来存储通过连接[5] 创建的新列表到你以前的 l 变量。

    【讨论】:

    • 谢谢你,非常清楚的解释。那么这是否会破坏 Elixir 擅长的并发性的整体不变性?这肯定会解决竞争条件和可变性带来的所有问题。
    • 我认为@ErrolHassall 你误解了一些东西。并发的问题是多个执行上下文(IE 线程、进程等)访问相同的物理内存位置。当 Elixir 重新绑定一个值时,反弹值被放置在不同的内存位置。
    • 是的,我忘记了那部分,感谢您添加。我只做了非常基本的并发工作
    【解决方案2】:

    可变性与不变性的问题更多是物理内存的问题。如果我要定义一个列表 l 并且它位于内存位置 1000 开始,然后多个线程/进程等都尝试一次追加到列表中,我遇到了决定谁的写入实际被处理以及在什么中处理的问题命令。另一方面,如果每次有人试图修改l 我将列表的内容复制到 1000 到一个新的内存地址,那么就不需要担心锁或互斥锁或任何类似的机制,因为每个线程/进程等正在获得自己的副本。

    注意,这是对幕后实际发生的事情的严重过度简化,但对于本次讨论,它本质上就是正在发生的事情。

    实际名称不如每次修改列表时都会将其复制到新的内存位置这一事实重要。

    如果我有

    l = [1, 2, 3, 4]
    

    它从内存 1000 开始

    然后我跑

    l = l ++ [5]
    

    然后丢弃 1000 处的 l,并在某个不同的内存位置创建一个新的 l。尽管名称相同,但它实际上是两个不同的内存位置。只要它们不共享内存位置,并发性就会明显容易得多,因为我不必处理锁或互斥锁或其他机制来处理同时发生的对同一物理内存地址的多次写入。

    【讨论】:

      猜你喜欢
      • 2020-03-23
      • 1970-01-01
      • 2015-07-10
      • 1970-01-01
      • 2012-03-10
      • 2021-10-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多