简体   繁体   中英

Elixir understanding GenServer

I am new to Elixir and was reading through a book and doing some examples. Here is the piece of code that makes me ask question here:

defmodule Sequence.Server do
    use GenServer
    def init(initial_number)do 
        {:ok,initial_number}
    end

    def handle_call(:next_number, _from, current_number)do
        {:reply, current_number,current_number+1}    
    end 
end

As I know the init function is called when the server is being initialized and we are defining some parameter - which will be the initial state of the server. The thing that makes me confused is that how current_number and the initial_number are related to each other, I mean nowhere in the code we are saying something like that

current_number = initial_number

Because when I call GenServer.call(some_process_id, :next_number) it starts from 100 for example if the parameter to start_link was 100. How does Elixir understands that it must start from 100 when we dont have any mapping between the initial state and the current_number parameters

The purpose of an init/1 is to setup up internal state of a GenServer . The only way to amend this GenServer 's internal state, is via call -ing, cast -ing, or sending regular messages (then, being handled by handle_info/2 callback).

Those functions (respectively, handle_call/3 and handle_cast/2 ) will be invoked with the GenServer 's internal state passed in as the last argument of a function's argument.

Consider the scenario:

  1. You're initialising the GenServer with number 100 .
  2. You send a message (a call to be more specific) to this GenServer - :next_number .
  3. This invokes your handle_call(:next_number, _from, current_number) callback function, where current_number has the initial value of 100 .
  4. As a return value from this function, you specified the tuple: {:reply, current_number,current_number+1} , which you should understand like: reply (first element of a tuple) indicates it will reply to the caller; the second element of the tuple will be the value returned to caller (in this case, it will be number 100 ); and the last element of the tuple will be the new state of a GenServer - current_number+1 , so 101 .
  5. When you send another :next_number call to this GenServer , it will follow the previous steps, except, the internal state will now be 101 , and after returning from the function, the new state will be 102 , etc...

The result of init is {:ok, initial_state} , where the state value is held by GenServer .

The signature of handle_call is actually handle_call(request, from, current_state) , and it returns {:reply, result, new_state} .

This means that when you do GenServer.call(pid, :next_number) , that results in a call to handle_call(:next_number, _from, state) , where the state -- passed as current_number -- starts as initial_number and the result of handle_call saves a new state with value current_number .

The next time you call GenServer.call(pid, :next_number) , it's called with the new state, and you return the new-new state, and so on...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM