gen_server handle_info/2 уточнение

Читая Erlang и OTP в действии, я наткнулся на какой-то странный синтаксис в отношении записей, который мне трудно понять. Я надеюсь, что кто-то может прояснить, что происходит в handle_info для тайм-аутов здесь:

handle_info({tcp, Socket, RawData}, State) ->
    do_rpc(Socket, RawData), 
    RequestCount = State#state.request_count, 
    {noreply, State#state{request_count = RequestCount + 1}}; 

handle_info(timeout, #state{lsock = LSock} = State) -> 
    {ok, _Sock} = gen_tcp:accept(LSock), 
    {noreply, State}.

В частности, я не совсем уверен, что здесь происходит:

#state{lsok = LSock} = State

Кажется, это какое-то обратное назначение? Фактически вы говорите, что вторым аргументом будет запись #state, чтобы присвоить значение lsock переменной LSock и присвоить всю запись State? Я просто делаю вывод из того, как переменные используются в следующих двух строках, но такой синтаксис кажется странным.

[РЕДАКТИРОВАТЬ]

Я провел еще несколько тестов сопоставления с образцом и присваивания в оболочке, и он не работает так, как я ожидал:

2> 1 = A.
* 1: variable 'A' is unbound
3> A = 1.
1
4> {1,2}.
{1,2}
5> {1,2} = B.
* 1: variable 'B' is unbound

Затем я запустил эту тестовую функцию, чтобы увидеть, может быть, это просто совпадение аргументов функции:

test_assignment(A = {X,Y},{W,X} = B) ->
    io:format("Variable A is ~p~n",[A]),
    io:format("Variable B is ~p~n",[B]).


24> c(test).                              
test.erl:21: Warning: variable 'W' is unused
test.erl:21: Warning: variable 'Y' is unused
{ok,test}
25> test:test_assignment({1,2},{3,4}).
** exception error: no function clause matching test:test_assignment({1,2},{3,4}) (test.erl, line 21)

person billcobbler    schedule 20.05.2015    source источник


Ответы (2)


Все определения параметров функций являются шаблонами, и

#state{lsock = LSock} = State

является одним шаблоном, который связывает State со всем термином, переданным в качестве аргумента вызова функции, и в то же время утверждает, что это состояние записи, и связывает State#state.lsock с LSock. В ваших примерах оболочки

A = 1.
1 = A.

являются выражениями соответствия, которые имеют форму

<pattern> = <expression>

и поэтому вы можете вводить и связывать новые переменные только слева от "=". Для примера, демонстрирующего совпадение со знаком равенства внутри шаблона, который вы можете легко запустить в оболочке erlang:

1> ({X,Y} = Z) = {1,2}.
{1,2}
2> X.
1
3> Y.
2
4> Z.
{1,2}

С другой стороны, ваш пример с

test:test_assignment({1,2},{3,4}).

вызывает ошибку, потому что в предложении функции, которое вы определили, X дважды используется в шаблонах {X, Y}, {Z, X}, которые не могут соответствовать аргументам, поскольку очевидно, что 1 не равно 4. Вы можете попробовать в оболочке:

5> TestAssignment = fun (A = {X, Y}, {W, X} = B) ->
5>   io:format("Variable A is ~p~n", [A]),
5>   io:format("Variable B is ~p~n", [B]) end.
6> TestAssignment ({1,2}, {3,4}).
** exception error: no function clause matching erl_eval:'-inside-an-interpreted-fun-'({1,2},{3,4}) 
7> TestAssignment ({1,2}, {3,1}).
Variable A is {1,2}
Variable B is {3,1}
ok

Обратите внимание, что выражение соответствия возвращает выражение rhs при совпадении. Теперь вы должны понять, почему это работает именно так:

10> 4 = C.
* 1: variable 'C' is unbound
11> C = 4.
4
% 4 = 4, so this matches and returns 4:
12> 4 = C.
4
% now C is bound, so this is a match 4 = 5, not <anything, that will be bound to C> = 5:
13> C = 5. 
** exception error: no match of right hand side value 5
person Nicole A.    schedule 21.05.2015
comment
Ах, теперь это имеет смысл. Я также не осознавал, что использовал X дважды! - person billcobbler; 21.05.2015

Помните, что «присваивание» в Erlang — это сопоставление с образцом. В контексте, указанном в вашем вопросе,

#state{lsock = LSock} = State

утверждает, что State привязано к значению, которое является записью #state{}, и в то же время связывает переменную LSock со значением поля lsock записи State.

person Steve Vinoski    schedule 20.05.2015
comment
Думаю, я не видел несвязанного присваивания в правой части совпадения с образцом. Я ожидаю, что это будет выглядеть так: State = #state{lsock = LSock} - person billcobbler; 21.05.2015
comment
Помните, что аргументы функции уже привязаны. Таким образом, этот код сопоставляет аргумент State с конструкцией записи #state{} и одновременно выполняет привязку LSock. Вы можете написать это любым способом (попробуйте!), но по моему опыту этот порядок чаще используется для аргументов. - person Steve Vinoski; 21.05.2015
comment
Поэтому я попробовал назначение несвязанных переменных в обратном порядке в оболочке, и это не работает. 2> 1 = A. * 1: variable 'A' is unbound 3> A = 1. 1 4> {1,2}. {1,2} 5> {1,2} = B. * 1: variable 'B' is unbound - person billcobbler; 21.05.2015
comment
Это не сработает, потому что вы пытаетесь сопоставить несвязанные переменные. Как я упоминал ранее, аргументы функции всегда уже привязаны, и это контекст для моего комментария, который вы можете написать в любом случае. Попробуйте это в оболочке, например: 1> F = fun(1=A) -> A; (A=2) -> A*2; (A) -> A*3 end. обратите внимание, как A соответствует в любом порядке в первых двух предложениях, а затем 2> {F(1), F(2), F(3)}. вернет {1,4,9}. - person Steve Vinoski; 21.05.2015