2016-03-28 67 views
0

所以我寫了兩個版本的gen_fsm來解析一個字節流。我正在尋找一個以字符串snp開頭的數據包,然後我想在p之後保存下一個20個字節。這段代碼只關心查找標題。我需要一些建議,指出哪一種是更加慣用的Erlang或更好的寫法。哪一種比較習慣?

選項1

parse_header({parse, Byte}, {Header, [Next | Rest]}) -> 
    case Byte of 
    Next when length(Rest) > 0 -> {next_state, parse_header, {Header, Rest}}; 
    Next when length(Rest) == 0 -> {next_state, parse_data, []}; 
    $s  -> parse_header({parse, Byte}, {Header, Header}); 
    _   -> {next_state, parse_header, {Header, Header}} 
end. 

選項2

parse_start({parse, Byte}, State) when Byte == $s -> 
    {next_state, parse_new, State}; 
parse_start({parse, Byte}, State) when Byte /= $s -> 
    {next_state, parse_start, State}. 

parse_new({parse, Byte}, State) when Byte == $n -> 
    {next_state, parse_packet, State}; 
parse_new({parse, Byte}, State) when Byte == $s -> 
    parse_start({parse, Byte}, State); 
parse_new({parse, _Byte}, State) -> 
    {next_state, parse_start, State}. 

parse_packet({parse, Byte}, State) when Byte == $p -> 
    {next_state, parse_data, State}; 
parse_packet({parse, Byte}, State) when Byte == $s -> 
    parse_start({parse, Byte}, State); 
parse_packet({parse, _Byte}, State) -> 
    {next_state, parse_start, State}. 

回答

1

兩種實現都很好,但是你應該更喜歡這最小化趟gen_fsm環的實現中,從而解析數據詳盡直到沒有別的東西需要解析,然後纔將控制權返回給gen_fsm

所以在這方面的第一個實施會更好。另外,較短的實現通常更容易推理,因此第一個解決方案再次是一個要點。

但是,第二種實現(可以說)更清晰,更適合gen_fsm方法,因此如果需要可能更容易維護和擴展。

也許你可以找到一個解決方案,從兩個最好的部分?例如,這個怎麼樣:

parse_header([ $s, $n, $p | Rest]) -> copy_data(Rest, 20, []); 
parse_header([ _ | T ]) -> parse_header(T); 
parse_header(List) when length(List) < 3 -> {next_state, parse_header}. 

copy_data(_, 0, Acc) -> lists:reverse(Acc); 
copy_data([], X, Acc) -> {next_state, {copy_data, X, Acc}}; 
copy_data([H | T], X, Acc) -> copy_data(T, X - 1, [H | Acc]). 

它試圖詳盡地讀取輸入,並且僅返回控制權交還給gen_fsm如果沒有更多的數據讀取。就像在第二個解決方案中一樣,它將解析標題與讀取數據分開。

這當然只是一個例子,如何解決問題,因爲我不知道你的其他代碼和你的確切需求。