Нужно ли экспортировать все функции в оболочку Erlang? - PullRequest
3 голосов
/ 07 февраля 2012

У меня есть этот код

start() ->
    spawn(?MODULE, init, [self()]).

init(From) ->
    spawn(?MODULE, broadcast, []).    

broadcast() ->
    Msg = "helloworld",
    timer:sleep(10000),
    broadcast().

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

Ответы [ 3 ]

5 голосов
/ 08 февраля 2012

Код

spawn(?MODULE, init, [self()]).

означает, что вы вызовете процесс, начальный вызов которого будет ?MODULE:init(self()) или, точнее, эквивалентным apply(?MODULE,init,[self()]). ?MODULE - это макрос, вычисляемый для текущего имени модуля, но в любом случае это внешний вызов функции, поэтому эту функцию необходимо экспортировать, даже если используется ?MODULE. Наоборот

spawn(fun() -> init(self()) end).

является порождением с первоначальным вызовом функции fun() -> init(self()) end, которая вызывает init/1 с результатом функции self(). Это локальный вызов, который означает, что init/1 не может быть экспортирован. Есть еще одна проблема, когда self() выполняется внутри нового процесса, поэтому вы должны написать

Self = self(), spawn(fun() -> init(Self) end).

для достижения того же эффекта, что и в spawn(?MODULE, init, [self()]), где self() оценивается как параметр spawn/3.

1 голос
/ 07 февраля 2012

хорошо, функция broadcast выполняется в процессе. Поэтому эта функция должна быть доступна для всех процессов. Даже если один и тот же фрагмент исходного кода в том же модуле порождает процесс, который выполняет функцию из того же модуля, эта функция должна быть экспортирована из этого модуля, чтобы сделать ее доступной.

Это подводит меня к разнице между spawn(fun() -> broadcast() end). и spawn(?MODULE, broadcast, []). Последний называется Spawning with <b>MFA</b>. В этом методе функция должна быть экспортирована из модуля, чтобы ее можно было выполнить. Первый, однако, уникален, его fun.

Чтобы понять этот метод: spawn(fun() -> broadcast() end)., нам нужно сравнить его с этим: spawn(fun() -> ?MODULE:broadcast() end).. Теперь давайте поговорим о позднем из двух


spawn(fun() -> ?MODULE:broadcast() end).

Теперь, если функция broadcast НЕ экспортируется в модуль: ?MODULE, процесс завершится сбоем. Обратите внимание, что в этом случае функция находится в том самом модуле, в котором написан этот фрагмент исходного кода.
spawn(fun() -> broadcast() end).

В этом случае функция должна находиться в том самом модуле, в котором написан этот фрагмент исходного кода. Тем не менее, я думаю, что компилятор преобразует это в приведенный выше, так что порожденный процесс говорит, что функция, которую вы ищете, находится в модуле ?MODULE.

Я не совсем гуру в компиляторах или системы времени выполнения, но я думаю, что вы будете использовать этот ответ. Мой сильный совет: в большинстве вашего исходного кода используйте это spawn(fun() -> ?MODULE:broadcast() end). или spawn(fun() -> some_module:broadcast() end)., даже если фрагмент кода или функция находится в том же самом модуле, чем этот: spawn(fun() -> broadcast() end).. Из моего личного опыта код становится управляемым и понятным. Я получаю эту приятную иллюзию, что порожденный процесс должен пойти и найти функцию из указанного модуля, а затем выполнить с заданными аргументами.
0 голосов
/ 07 февраля 2012

Посмотрите внимательнее на предупреждения:

test.erl:8: Warning: function init/1 is unused
test.erl:8: Warning: variable 'From' is unused
test.erl:11: Warning: function broadcast/0 is unused
test.erl:12: Warning: variable 'Msg' is unused

Компилятор считает, что ваши другие функции не используются, и никогда не компилирует их. Попробуйте вместо этого:

start() ->
    spawn(fun() -> init(self()) end).

init(From) ->
    spawn(fun() -> broadcast() end).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...