状態管理のためのGenStatem
GenStatemを使って堅牢な有限状態機械を構築し、複雑な状態遷移を管理してイベントを効果的に処理する方法を習得します。
「状態管理のためのGenStatem」はCoddyKit上の無料Erlang OTP: Distributed & Fault-Tolerant Systems Programmingレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはErlang OTP: Distributed & Fault-Tolerant Systems Programming学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Erlang OTP: Distributed & Fault-Tolerant Systems Programmingコースには全4レッスンが含まれています。
このレッスンの一部はまだ翻訳されておらず、英語で表示されています。
Meet GenStatem
Welcome to GenStatem! It's an OTP behavior in Erlang used to build Finite State Machines (FSMs). If your system component needs to behave differently based on its current state, GenStatem is your friend.
Think of it as a specialized tool for managing complex state logic, offering more explicit control over state transitions than a regular GenServer.
FSM Fundamentals
A Finite State Machine (FSM) is a mathematical model of computation that describes the behavior of a system. It can only be in one state at any given time.
- States: Distinct conditions a system can be in (e.g., "on", "off", "idle", "active").
- Events: Inputs or occurrences that trigger a change in state (e.g., "button_press", "timeout").
- Transitions: Rules that define how an event in a particular state causes a shift to a new state.
GenStatem Module Basics
Like other OTP behaviors, GenStatem requires a callback module. This module implements specific functions that define the FSM's behavior.
The most basic function is init/1, which sets up the initial state and data for your FSM. It returns {:ok, InitialState, InitialStateData}.
-module(my_fsm).
-behaviour(gen_statem).
-export([start_link/0]).
-export([init/1]).
-export([callback_mode/0]).
% Minimal init for a GenStatem
init(_Args) ->
io:format("FSM initializing...~n"),
InitialState = off, % Our first state
InitialStateData = [], % Any data we want to carry
{:ok, InitialState, InitialStateData}.
% Defines how events are handled (state-name based)
callback_mode() ->
state_functions.
start_link() ->
gen_statem:start_link({local, ?MODULE}, ?MODULE, [], []).States and StateData
In GenStatem, a state is typically an atom (e.g., :on, :off). StateData is any Erlang term that holds the internal information associated with the current state, similar to a GenServer's state.
When you transition, you specify both the new state atom and the new state data. This allows you to carry context and information across different states of your FSM.
Responding to Events
GenStatem uses callback functions to react to events. For asynchronous events (like gen_statem:cast/2), the handle_event/4 callback is used.
The function signature is State(EventType, EventContent, StateData), where State is the current state atom and EventType indicates the type of message (e.g., :cast, :info).
% Example for 'off' state
off(cast, toggle, StateData) ->
io:format("Switching to ON from OFF~n"),
{:next_state, on, StateData}; % Transition to 'on' state
off(info, _Msg, StateData) ->
io:format("Received info in OFF state~n"),
{:next_state, off, StateData}.Changing States
The return value of your event-handling functions dictates the FSM's next action. To change state, you return a tuple: {:next_state, NewState, NewStateData}.
NewState: The atom representing the next state.NewStateData: The updated state data to be carried into the new state.
If you want to stay in the current state, you can return {:keep_state, NewStateData} or {:keep_state_and_data} if data doesn't change.
Sync vs. Async Events
GenStatem handles different types of events:
handle_call/4: For synchronous calls (gen_statem:call/3). The caller waits for a reply.handle_event/4: For asynchronous casts (gen_statem:cast/2) and internal messages (gen_statem:info/2, or process messages). The caller does not wait.handle_info/4: A specialized version ofhandle_eventfor process messages not originating fromgen_statem:castorgen_statem:call. Often less used withstate_functionsmode.
We'll focus on handle_call and handle_event in our example.
Light Switch Example
Let's build a classic FSM: a light switch! It will have two states: off and on.
We'll send a toggle event to change its state. We'll also add a way to check its current status.
Light Switch Code
Here's the full Erlang module for our light switch. Run it and try interacting with it!
-module(light_switch).
-behaviour(gen_statem).
-export([start_link/0, toggle/0, status/0]).
-export([init/1, callback_mode/0]).
-export([off/4, on/4]). % Export state functions
% -- Public API --
start_link() ->
gen_statem:start_link({local, ?MODULE}, ?MODULE, [], []).
toggle() ->
gen_statem:cast(?MODULE, toggle).
status() ->
gen_statem:call(?MODULE, status).
% -- GenStatem Callbacks --
init(_Args) ->
io:format("Light switch initializing to OFF~n"),
{:ok, off, []}. % Initial state 'off', no specific data
callback_mode() ->
state_functions.
% -- State 'off' callbacks --
off(cast, toggle, StateData) ->
io:format("Switching from OFF to ON~n"),
{:next_state, on, StateData};
off(call, status, From, StateData) ->
gen_statem:reply(From, off),
{:keep_state, StateData};
off(EventType, EventContent, StateData) ->
io:format("OFF state received unhandled event: ~p, ~p~n", [EventType, EventContent]),
{:keep_state, StateData}.
% -- State 'on' callbacks --
on(cast, toggle, StateData) ->
io:format("Switching from ON to OFF~n"),
{:next_state, off, StateData};
on(call, status, From, StateData) ->
gen_statem:reply(From, on),
{:keep_state, StateData};
on(EventType, EventContent, StateData) ->
io:format("ON state received unhandled event: ~p, ~p~n", [EventType, EventContent]),
{:keep_state, StateData}.
% --- How to run this code in Erlang shell: ---
% c(light_switch).
% light_switch:start_link().
% light_switch:status(). % Should be 'off'
% light_switch:toggle().
% light_switch:status(). % Should be 'on'
% light_switch:toggle().
% light_switch:status(). % Should be 'off'
GenStatem Challenge
Consider a GenStatem module representing a door with states :closed and :open. It receives :open_door and :close_door events.
If the door is :closed and receives :open_door, it transitions to :open. If it's :open and receives :close_door, it transitions to :closed.
What is the correct return value from the closed/4 state function when it receives an :open_door event via gen_statem:cast/2?
GenStatem Summary
Great job mastering GenStatem!
You've learned that GenStatem is ideal for implementing Finite State Machines, allowing you to manage complex state-dependent logic. Key takeaways:
- FSMs have states, events, and transitions.
- GenStatem uses callback modules and state functions (e.g.,
off/4,on/4). - You transition between states using
{:next_state, NewState, NewStateData}. - Events can be asynchronous (
cast, handled byhandle_event/4) or synchronous (call, handled byhandle_call/4).
This powerful behavior is a cornerstone for building robust, predictable systems in Erlang.
よくある質問
「状態管理のためのGenStatem」レッスンは無料ですか?
はい。「状態管理のためのGenStatem」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Erlang OTP: Distributed & Fault-Tolerant Systems Programmingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Erlang OTP: Distributed & Fault-Tolerant Systems Programmingコースには全4レッスンが含まれています。
「状態管理のためのGenStatem」で何を学びますか?
GenStatemを使って堅牢な有限状態機械を構築し、複雑な状態遷移を管理してイベントを効果的に処理する方法を習得します。 ブラウザで直接実行するハンズオンコードでErlang OTP: Distributed & Fault-Tolerant Systems Programmingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Erlang OTP: Distributed & Fault-Tolerant Systems Programmingを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのErlang OTP: Distributed & Fault-Tolerant Systems Programmingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「状態管理のためのGenStatem」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このErlang OTP: Distributed & Fault-Tolerant Systems Programmingレッスンでコードを書いて実行できますか?
はい。すべてのErlang OTP: Distributed & Fault-Tolerant Systems Programmingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 状態管理のためのGenStatem
- イベント処理のためのGenEvent
- カスタムOTPビヘイビア
- ホットコードスワップとライブアップグレード