wxErlang 的案例學習(1)

來源:互聯網
上載者:User

這些天,一直在鼓搗wxWidgets。裝上了code::blocks,學了bakefile,為的是輔助使用wxErlang。

前期的鋪墊告一段落,正戲開場。

一直以為,學習也要講效率,學以致用,沒用的不學。要真正做到這點,不難,集中精力學習examples就行。

examples集中了知識精華,展示了技術訣竅,是把握關鍵技術的捷徑。

學習examples,全面深入地琢磨程式的運行機制,有助於理解掌握技術細節。

挑選的案例,是erl5.7.1/lib/wx-0.98.1/examples/sudoku。其中有4個erl模組,將挨個詳細解剖分析。

一、模組sudoku.erl

-module(sudoku).

-export([go/0]).

-compile(export_all).

-include("sudoku.hrl").

start() -> 

    spawn_link(fun() -> init(halt) end).

go() -> 

    spawn_link(fun() -> init(keep) end).

init(Halt) ->

    ?TC(sudoku_gui:new(self())),

    receive {gfx, GFX} -> ok end,

    case sudoku_game:init(GFX) of

Halt -> erlang:halt();

Stop -> exit(Stop)

    end.

tc(Fun,Mod,Line) ->

    case timer:tc(erlang, apply, [Fun,[]]) of

        {_,{'EXIT',Reason}} -> exit(Reason);

        {T,R} ->

            io:format("~p:~p: Time: ~p/n", [Mod, Line, T]),

            R

    end.

(1)、編譯指令-export([go/0])和-compile(export_all)

-export([go/0])是說,其他模組可以在源碼級調用本模組的函數go,即:sudoku:go().

-compile(export_all)是說,本模組編譯成.beam後,全部函數均開放調用。

例如,在eshell中,直接調用以下函數都是允許的:

3> sudoku:init(keep).

4> sudoku:tc(fun() -> sudoku_gui:new(self()) end, sudoku, 40). 

可是,如果屏蔽指令 %% -compile(export_all),將只能調用 sudoku:go(),否則,會出錯:

10> sudoku:init(keep).                                             

** exception error: undefined function sudoku:init/1

(2)spawn與spawn_link的主要區別

這是並發編程的基本問題。Erlang把建立進程,叫做“spawn”的用意,是為了突出進程的主從關係。“spawn”是孵化的意思,產生的是子進程。

建立進程的函數有2個,spawn與spawn_link。二者的主要區別在於,spawn出的進程意外崩潰後,不影響父進程的運行;spawn_link出的進程意外崩潰後,則連帶父進程一併停運。

(3)GUI子進程的初始化與停運

本模組中有一函數init/1,它掌控著GUI子進程的初始化,和程式進程的停運。這個函數做5件事:

①調用模組sudoku_gui的函數new/1

②監測函數sudoku_gui:new/1的運行用時

③接收來自sudoku_gui的訊息{gfx,GFX}

④調用sudoku_game:init(GFX)

⑤根據sudoku_game:init(GFX)返回的值,確定進程的終止或異常退出

第①和第②這兩件事情,是用“宏” ?TC(sudoku_gui:new(self()))完成的,它是個函數調用的嵌套語句,很有Erlang的特色。

宏TC定義在sudoku.hrl

-define(TC(Cmd), tc(fun() -> Cmd end, ?MODULE, ?LINE)).

把它展開,就是 tc(fun() -> sudoku_gui:new(self()) end, ?MODULE, ?LINE)

函數tc/3是在本模組中定義的,第一參數是個函數,第二參數?MODULE是本模組名字(sudoku),第三參數是該語句所在的行。

可以在函數tc/3中顯示一下,會看清楚:

tc(Fun,Mod,Line) ->

    io:fwrite("~ntc(~p,~p,~p)~n",[Fun,Mod,Line]),

    ……

第③件事情,語句 receive {gfx, GFX} -> ok end,接收來自sudoku_gui的訊息。

為什麼說是來自sudoku_gui的訊息呢?函數調用sudoku_gui:new(self())中的參數self,本進程的Pid,告知對方是為了通訊聯絡。

可用語句io:fwrite("~nself() = ~p~n",[self()])顯示看看Pid的尊容,如:self() = <0.41.0>

第④和第⑤兩件事情,是由一個case結構完成的:

case sudoku_game:init(GFX) of

    Halt -> erlang:halt();

    Stop -> exit(Stop)

end.

涉及sudoku_gui和sudoku_game兩個模組的事情,以後細聊,這裡只說本模組內的事兒。

這個case主管主進程的終止退出。Halt的值是原子halt或keep,來自本模組的函數start()或go()。

erlang:halt()進程正常終止,exit(Stop)進程異常退出,Stop是異常的資訊提示。

(4)有意思的函數tc/3

這個函數名字的意思是time counter,“計時器”。

這個函數也很能體現Erlang函數編程特色。

timer:tc(erlang, apply, [Fun,[]]),是個高階函數,即把函數當成參數值使用的函數。

apply和Fun都是函數。apply是erlang內建函數,Fun是sudoku_gui:new(self())。

我們做個實驗,看看apply()和timer:tc()的工作情況。

    49> W= fun(X)-> io:fwrite("~n~s~n",[X])end.

        #Fun<erl_eval.6.13229925>

    50> apply(W,["i am a worker"]).            

        i am a worker

        ok

    51> 

    52> timer:tc(erlang, apply, [W,["kjkjkjkjk"]]). 

         kjkjkjkjk

         {100000,ok}

    53> 

case timer:tc(erlang, apply, [Fun,[]]) of

    {_,{'EXIT',Reason}} -> exit(Reason);

    {T,R} ->

        io:format("~p:~p: Time: ~p/n", [Mod, Line, T]),

        R

end.

case中函數Fun執行的兩個結果,{_,{'EXIT',Reason}}是發生異常,將導致退出exit(Reason);

另一結果{T,R},即{Time,Result},正常。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.