# Ruby 周末练习：如何用 Ruby 写出可读性高的状态机代码

HalF_taN · 2014年04月19日 · 最后由 wujian_hit 回复于 2014年05月10日 · 3636 次阅读

``````/*
* init  = initial state
* op_in = operator loaded in
* eql   = equal sign loaded in
*
* |    States   |   input    |   transition to
* |             |            |
* |    init     |   digit    |   init
* |    init     |   * + -    |   op_in ( with target transfer )
* |    init     |   key_ac   |   init ( with resetting )
* |    op_in    |   digit    |   op_in
* |    op_in    |   * + -    |   op_in ( with calculation being done )
* |    op_in    |   key_ac   |   init ( with resetting )
* |    op_in    |   key_eql  |   init ( with calculation being done )
*/

/*
* where calculation actually being done.
* @param: [int op] loaded operator
* @param: [int lhs] left hand side operand
* @param: [int rhs] right hand side operand
* @return: result of the calculation
*/
static int do_calc(int op, int lhs, int rhs);

void calculator(void)
{
some_init_proc();
int i;
int lhs, rhs, *target;
int state, op;

lhs = rhs = 0;
target = &lhs;
display_num(0);

// State INIT
while (1) {
init:
if (i < 10) {
*target *= 10;
*target += i;
display_num(*target);
} else if (i == KEY_AC) {
lhs = rhs = 0;
target = &lhs;
display_num(0);
goto init;
} else if (i == '+' || i == '-' || i == '*') {
target = &rhs;
op = i;
goto op_in;
}
}

// State OP_IN
while (1) {
op_in:
if (i < 10) {
*target *= 10;
*target += i;
display_num(*target);
} else if (i == KEY_AC) {
lhs = rhs = 0;
target = &lhs;
display_num(0);
goto init;
} else if (i == '+' || i == '-' || i == '*') {
target = &rhs;
lhs = do_calc(op, lhs, rhs);
display_num(lhs);
op = i;
goto op_in;
} else if (i == KEY_EQL) {
lhs = do_calc(op, lhs, rhs);
display_num(lhs);
goto equ;
}
}

// State EQL
while (1) {
eql:
if (i == KEY_AC) {
target = &lhs;
lhs = rhs = 0;
op = '+';
goto init;
}
}
}

int do_calc(int op, int lhs, int rhs)
{
switch (op) {
case '+':
return lhs + rhs;
case '-':
return lhs - rhs;
case '*':
return lhs * rhs;
default:
return lhs + rhs;
}
}
``````

#1 楼 @lyfi2003 我用的另外一个，当时觉得比 state_machine 简单点

https://github.com/aasm/aasm

#1 楼 @lyfi2003 #2 楼 @Victor 用 Gem 当然是可以解决这个问题，但是锻炼自己思维能力的目的就达不到了啊。 我想能不能利用`send``method_missing`，还有`singleton method`来实现，比如：

``````while has_input?
current_state = current_state.send next_input
end
``````

@HalF_taN 我的意思是参考下它的源代码~

#4 楼 @lyfi2003 嗯，这倒是可以。不过总有种做作业偷看答案的感觉

#5 楼 @HalF_taN 先模仿，再学习，是个正常的过程:)

`goto` 是一种`continuation`，而：

a continuation is an abstract representation of the control state of a computer program