零基础开发 era 游戏 #6 函数的定义和使用

在 era 游戏里的「函数」是一个很奇怪的东西。
为什么要打引号呢?因为他所谓的「関数」指他自创的新概念函数。

据说是跟日语 IT 圈结合日本文化环境的特殊语境下有关。

总之 Emuera 日语文档里说的「関数」,跟地球上其他地区的程序员圈子里常识概念上的「函数」,有一定区别。

两种不同类型的函数之间的区别#

一般函数(命令)#

  1. 必须用 CALL 命令调用(或 JUMP 命令跳转)。
  2. 「返回值」返回(RETURN / RETURNFORM)到全局公共变量 RESULT(数值)里。
  3. 定义时不用加修饰符。

有些系统内置的一般函数(命令)同时还会「返回」RESULTS(字符串)。
其实只是 RESULTS = 新的结果 而已,这就是一般「函数」的「返回值」的本质:
用一个 全局 公共 变量,来临时存放处理后的结果。

行内函数(真正的函数)#

  1. 可以且只能直接用在表达式里(不能被 CALL / JUMP)。
  2. 「返回值」返回到(RETURNF)到原本调用它的地方。
  3. 定义时必须加修饰符(#FUNCTION数值 / #FUNCTIONS字符串),用来限定返回值的数据类型。

其他对比#

参数的定义 / 传递方式

函数(无论是一般函数还是行内函数)的参数定义格式无论是使用 () 还是 , 都行。

但只有一般函数支持用两种形式调用:

@SYSTEM_TITLE
    CALL DO_SOMETHING, "发呆"
    CALL DO_OTHER_THING("什么都没做")
    QUIT


@DO_SOMETHING(sth)
    #DIMS sth
    PRINTFORML 做了一些事:%sth%
    RETURN


@DO_OTHER_THING, sth
    #DIMS sth
    PRINTFORML 做了其他事:%sth%
    RETURN

行内函数除了调用时需要注意一下,定义时使用不同的参数写法实际并无区别:

@SYSTEM_TITLE
    ; 给行内函数传参必须用括号包起来 否则会报错「は解釈できない識別子です」
    PRINTFORML %DO_SOMETHING("发呆")%
    PRINTFORML %DO_OTHER_THING("什么都没做")%
    QUIT


@DO_SOMETHING(sth)
#FUNCTIONS
    #DIMS sth
    RETURNF @"做了一些事:%sth%"


@DO_OTHER_THING, sth
#FUNCTIONS
    #DIMS sth
    RETURNF @"做了其他事:%sth%"

一般函数(命令)#

定义#

@DO_SOMETHING(num)
    #DIM num
    RESULTS = 做了一些事
    RETURN num + 1


@DO_OTHER_THING(num)
    #DIM num
    RESULTS = 做了其他事
    RETURNFORM 10{num}

使用#

@SYSTEM_TITLE
    CALL DO_SOMETHING(111)
    PRINTFORML DO_SOMETHING(111) → RESULT={RESULT} RESULTS=%RESULTS%
    CALL DO_OTHER_THING(999)
    PRINTFORML DO_OTHER_THING(999) → RESULT={RESULT} RESULTS=%RESULTS%
    QUIT

CALL

@SYSTEM_TITLE
    CALL SOMEDAY
    QUIT


@SOMEDAY
    PRINTL 今天天气很好
    PRINTL 恰巧路过一个公园
    CALL TEST_EVENT
    PRINTL 回到公园入口 继续沿原路回家
    PRINTL 完美的一天


@TEST_EVENT
    PRINTL 于是进去逛了一会
    PRINTL 心旷神怡

使用 CALL 调用的函数运行结束后会回到原处。示例程序的结果:

今天天气很好
恰巧路过一个公园
于是进去逛了一会
心旷神怡
回到公园入口 继续沿原路回家
完美的一天

JUMP

@SYSTEM_TITLE
    CALL SOMEDAY
    QUIT


@SOMEDAY
    PRINTL 今天天气很好
    PRINTL 准备回家时被前辈叫住
    JUMP TEST_EVENT
    ; 由于是直接「跳转」到目标函数 当目标函数运行完成后 本函数直接结束
    PRINTL 回家路上遭遇无差别杀人魔
    PRINTL 你遇害了


@TEST_EVENT
    PRINTL 前辈邀请你吃饭 你欣然前往
    PRINTL 愉快的用餐后 前辈开车送你回家
    PRINTL 完美的一天

使用 JUMP 跳转的函数运行结束后视为「跳转时的函数也执行结束」。示例程序的结果:

今天天气很好
准备回家时被前辈叫住
前辈邀请你吃饭 你欣然前往
愉快的用餐后 前辈开车送你回家
完美的一天

行内函数(真正的函数)#

定义#

@GET_NUMBER(num)
#FUNCTION
    #DIM num
    RETURNF num + 233


@GET_STRING(text)
#FUNCTIONS
    #DIMS text
    RETURNF "兄弟们!有" + text + "!"

使用#

直接插入表达式行内

@SYSTEM_TITLE
    PRINTFORML 我去!{GET_NUMBER(767)}!%GET_STRING("狗")%
    QUIT

本地(局部)变量#

LOCAL / LOCALS,这是一组仅在函数内部生效的的变量。
可以用 #LOCALSIZE / #LOCALSIZES 修饰符来单独限定变量(数组)的大小。
(若没有手动指定,则默认使用 ./csv/VariableSize.csv 里设定的数组大小。)

究其本质,它实际上不是所谓的局部变量——
而是名为 LOCAL@函数名LOCALS@函数名 的 public static 变量。

即使离开函数,该值也会被保存;从函数之外也能引用(甚至修改)。
另外,在像是循环 / 递归之类的多次调用的情况下也会共享同一个值。

@SYSTEM_TITLE
    WHILE 1
        INPUT
        PRINTFORML 输入了 RESULT={RESULT}
        CALL TEST_COM
        PRINTFORML CALL TEST_COM 之后 LOCAL@TEST_COM={LOCAL@TEST_COM}
        PRINTFORML TEST_FUNC()={TEST_FUNC()}(LOCAL:1) 之后 LOCAL@TEST_FUNC={LOCAL@TEST_FUNC}(LOCAL:0)
        PRINTL
    WEND
    QUIT


@TEST_COM
    #LOCALSIZE 1
    LOCAL += 1


@TEST_FUNC
#FUNCTION
    #LOCALSIZE 2
    LOCAL:0 += 1
    LOCAL:1 += 10
    RETURNF LOCAL:1

如果你的函数只需要一个自变量,可以直接使用 LOCAL / LOCALS
但最好尽量使用 #LOCALSIZE / #LOCALSIZES 限定所需的大小,并且谨记在每次调用该函数的时候,一般都需要先初始化该变量。

除非你有特别的需求,比如把 LOCAL / LOCALS 这个值作为某种临时的「属性」。

lackbfun © 2021 - 2024