โครงสร้าง Elixir ไม่สามารถเปลี่ยนรูปได้จริงหรือ? [ทำซ้ำ]

ขณะนี้ฉันกำลังศึกษา Elixir และกำลังอ่าน "การพัฒนาเว็บเชิงฟังก์ชันด้วย Elixir, OTP และ Phoenix" ซึ่ง imo เป็นหนังสือที่ยอดเยี่ยม เมื่อทำงานที่บท state machine ฉันได้รหัสต่อไปนี้:

defmodule IslandsEngine.Rules do
  alias __MODULE__

  defstruct state: :initialized

  def new(), do: %Rules{}

  def check(%Rules{state: :initialized} = rules, :add_player), do:
    {:ok, %Rules{rules | state: :players_set}}

  def check(_state, _action), do: :error

end

โค้ดด้านบนควรทำงานเป็นเครื่องสถานะที่ทำงานได้อย่างสมบูรณ์ ฉันจะวางคำสั่ง iex ไว้ด้านบน:

iex(1)> alias IslandsEngine.Rules
IslandsEngine.Rules

iex(2)> rules = Rules.new()
%IslandsEngine.Rules{state: :initialized}

iex(3)> {:ok, rules} = Rules.check(rules, :add_player)
{:ok, %IslandsEngine.Rules{state: :players_set}}

iex(4)> rules.state
:players_set

อย่างที่คุณเห็น โครงสร้างสถานะได้เปลี่ยนจาก :initialized เป็น :add_player ยอดเยี่ยม.

คำถามของฉันคือ state: struct ไม่เปลี่ยนรูปจริงหรือ ฉันหมายถึงว่าเมธอด check/1 ส่งคืนสำเนาของโครงสร้างด้วยคำสั่ง state: :players_set ซึ่งเป็นไปตามรูปแบบการทำงานที่ถูกต้อง... แต่มันจะ "เขียนทับ" สถานะปัจจุบันโดยไม่ต้องแก้ไขโดยตรงได้อย่างไร

ขอบคุณมาก!


person Michele Riva    schedule 01.11.2018    source แหล่งที่มา
comment
เพิ่งรู้ว่ามีคำถามที่มีอยู่พร้อมคำตอบซึ่งครอบคลุมรายละเอียดมากขึ้น: ตัวแปร Elixir ไม่เปลี่ยนรูปจริงๆ หรือไม่ ?   -  person Sheharyar    schedule 01.11.2018
comment
คำถาม/คำตอบที่น่าสนใจอีกข้อหนึ่งซึ่งอาจช่วยอธิบายบางสิ่งเพิ่มเติม: Elixir: Rational behind อนุญาตให้เชื่อมโยงตัวแปรใหม่   -  person Sheharyar    schedule 01.11.2018


คำตอบ (1)


โครงสร้างข้อมูล Elixir นั้นไม่เปลี่ยนรูปอย่างแน่นอน แต่สิ่งที่เกิดขึ้นคือ การเรียกใช้ฟังก์ชันส่งคืนค่าใหม่ทั้งหมด (ซึ่งแตกต่างจากค่าเดิม ขึ้นอยู่กับฟังก์ชันที่คุณเรียกใช้)

สำหรับ "การเปลี่ยนค่าของตัวแปร" นั่นคือคุณสมบัติที่เพิ่มเข้ามา ใน Elixir (มากกว่าภาษาต้นฉบับ Erlang) ค่าของตัวแปรไม่ได้เปลี่ยนแปลงจริงๆ เพียงแต่ถูกเชื่อมโยงกับค่าใหม่เท่านั้น อันเก่าจะถูกรวบรวมโดยอัตโนมัติโดย Erlang VM.


ดังนั้นในตัวอย่างของคุณ:

# This returns a completely new `%Rules{}` struct and rebinds
# the `rules` variable to the new term
{:ok, rules} = Rules.check(rules, :add_player)
person Sheharyar    schedule 01.11.2018