lua 函数条件与返回的区别是什么?


1.


 function dum(t)
  if t then return 1 end
  return 0
end

2.


 function dum(t)
  if t then return 1 else return 0 end
end

上面两个函数在功能上是一样的,只是实现上有一些差别。

疑惑是

  1. 它们在语义上是否有差别?
  2. 它们在编译器中的实现方式是否相同?
  3. 在逻辑上,这两个函数是否完全一致?

希望能够能得到详解。谢谢!

编译原理 lua

真希波マリ 10 years ago

有一小点点区别,我这里先说一下查看Lua(我指的是其官方实现)汇编的方法吧。
luac -l src.lua 就可以在stdout上打印出 src.lua 生成的Lua VM字节码,并且是已经反汇编好了的。有了这个小技巧,我们就可以开始之后的讨论了。
我把你的这两个函数分别改名为 dum1() dum2() ,顺带帮你写了个 dum3() ,程序内容和Lua反汇编结果如下:


  ~/ cat -n test.lua
     1  function dum1(t)
     2          if t then return 1 end
     3          return 0
     4  end
     5
     6  function dum2(t)
     7          if t then return 1 else return 0 end
     8  end
     9
    10  function dum3(t)
    11          return t and 1 or 0
    12  end
    13      
 ~/ luac -l test.lua

main <test.lua:0,0> (7 instructions at 0x7f85f1405a00)
0+ params, 2 slots, 1 upvalue, 0 locals, 3 constants, 3 functions
        1       [4]     CLOSURE         0 0     ; 0x7f85f1405c40
        2       [1]     SETTABUP        0 -1 0  ; _ENV "dum1"
        3       [8]     CLOSURE         0 1     ; 0x7f85f1405fe0
        4       [6]     SETTABUP        0 -2 0  ; _ENV "dum2"
        5       [12]    CLOSURE         0 2     ; 0x7f85f14060e0
        6       [10]    SETTABUP        0 -3 0  ; _ENV "dum3"
        7       [12]    RETURN          0 1

function <test.lua:1,4> (7 instructions at 0x7f85f1405c40)
1 param, 2 slots, 0 upvalues, 1 local, 2 constants, 0 functions
        1       [2]     TEST            0 0
        2       [2]     JMP             0 2     ; to 5
        3       [2]     LOADK           1 -1    ; 1
        4       [2]     RETURN          1 2
        5       [3]     LOADK           1 -2    ; 0
        6       [3]     RETURN          1 2
        7       [4]     RETURN          0 1

function <test.lua:6,8> (8 instructions at 0x7f85f1405fe0)
1 param, 2 slots, 0 upvalues, 1 local, 2 constants, 0 functions
        1       [7]     TEST            0 0
        2       [7]     JMP             0 3     ; to 6
        3       [7]     LOADK           1 -1    ; 1
        4       [7]     RETURN          1 2
        5       [7]     JMP             0 2     ; to 8
        6       [7]     LOADK           1 -2    ; 0
        7       [7]     RETURN          1 2
        8       [8]     RETURN          0 1

function <test.lua:10,12> (8 instructions at 0x7f85f14060e0)
1 param, 2 slots, 0 upvalues, 1 local, 2 constants, 0 functions
        1       [11]    TEST            0 0
        2       [11]    JMP             0 3     ; to 6
        3       [11]    LOADK           1 -1    ; 1
        4       [11]    TEST            1 1
        5       [11]    JMP             0 1     ; to 7
        6       [11]    LOADK           1 -2    ; 0
        7       [11]    RETURN          1 2
        8       [12]    RETURN          0 1

从实际的运行效果来说,这3个版本的 dum() 都是一样的(如果t不是false或者nil就返回1,否则返回0),但是实际运行起来略有一小点差别: dum3() 会比前两个版本要多执行一个判断(因为Lua编译器没做什么优化,所以那个1还是要判断一下的)。 dum1() dum2() 之间虽然后者比前者多编译出了一条JMP语句,但是由于这条JMP语句是在RETURN之后的,所以并不会影响程序实际的运行流程。
总结起来就是,这3个版本的 dum() 语义没有差别,运行的结果也一样,但是编译出来的语句略有差别:其中 dum1() dum2() 运行流程一致, dum3() 会多对常数1进行判断。

ruben answered 10 years ago

Your Answer