Gox语言快速入门:一个计算BMI指数的实例-GX3

为了介绍Gox语言的基本用法,本篇将介绍一个用表达式进行日常数学计算的实例,用一个有趣而有用的数学算式来进行。

首先引入体重指数的概念,体重指数(Body Mass Index,简称BMI)是国际上常用于衡量人体胖瘦程度以及是否健康的一个标准,它的公式是 BMI = W ÷ H2,其中BMI是体重指数(严谨地说应该叫身体质量指数,mass是物理上质量的意思)的缩写,W指人的体重(单位是千克),H指人的身高(单位是米)。通过每个人体重指数所处的范围,可以辅助对其进行一定的分类以供统计。本书并不讨论这个标准的合理性和适用性,仅用该指数的公式来示范在Gox语言中利用表达式进行计算和处理的过程,以及基本的语言文法。

BMI体重指数的公式可以用表达式来表示如下:

BMI = W / (H * H)

这是因为H2 = H * H,所以该表达式与体重指数公式是等价的。

对于成人,目前用于中国的分类标准大致是:

偏瘦:BMI < 18.5
正常:18.5 <= BMI < 24
偏胖:24 <= BMI < 28
肥胖:28 <= BMI < 30
重度肥胖:BMI >= 30

用代码实现计算体重指数并进行分类判断的代码如下:

W = 65.0
H = 1.75

BMI = W / (H * H)

pl("BMI: %.2f", BMI)

if BMI < 18.5 {
    println("偏瘦")
} elif (18.5 <= BMI) && (BMI < 24) {
    println("正常")
} elif 24 <= BMI && BMI < 28 {
    println("偏胖")
} elif 28 <= BMI && BMI < 30 {
    println("肥胖")
} elif BMI >= 30 {
    println("重度肥胖")
}

上面的代码中,首先将表示体重的变量W赋值为65.0,将表示身高的变量H赋值为1.75,然后用表达式W / (H * H) 计算出体重指数并赋值给变量BMI。注意变量W特地在赋值的时候写作65.0,是因为后面的身高变量H必然是浮点数,而为了在后面的表达式中保证W和H的数据类型一致(否则会在编译时报错),所以即使体重一般都是整数也把它写作浮点数。另外,输出BMI数值时使用了%.2f的格式化符,表示小数点后仅保留两位。

pl和println都是Gox语言内置的函数,用于向命令行界面输出信息,pl相当于Go语言或Java、C语言中printf,但多输出一个回车换行符;println则与这些语言中的println函数功能完全相同。

然后的代码是一组条件判断语句,用于根据BMI的数值范围来将测试者进行分类。这种连续的if和elif组成的条件判断语句群是常见的实现分类逻辑的代码。条件判断的顺序会从第一个if语句后的条件开始进行判断,如果满足该条件则执行该分支的代码并不再执行后续的所有else if条件判断语句,如果不满足该条件则继续执行下面紧接着的else if条件判断语句,并继续按上述逻辑直至最后一条else if条件判断语句。有时候,在最后会用一个else分支来将所有剩余的情况一起处理。

  • 注意,一般语言中(例如Go语言和C++、Java等),条件判断中一般用“else if”表示分支。而Gox语言用简化的“elif”,这是初用Gox语言比较容易出问题的地方。

上面代码假设保存于bmi1.gox文件中,用gox bmi1.gox命令行执行后的结果是,

BMI: 21.22
正常
[7 <nil>]

可以看出,一个体重65公斤、身高1.75米的成人的体重指数BMI为21.22,属于“正常”的范围内。

程序执行末尾,输出了一个类似[7 <nil>]的数值,这是因为Gox语言是一个“可计算值”的语言,简单地说就是程序执行后,如果最后一条语句是可以计算值的(即可以看做表达式),则会将最后一个表达式的值输出。由于println函数是有输出值的,会将命令行输出内容的长度返回,因此会出现这样的结果。如果不想输出值,可以在程序的最后加一条调用pass()函数的语句,就不会输出多余信息了。如下面所示:

W = 65.0
H = 1.75

BMI = W / (H * H)

pl("BMI: %.2f", BMI)

if BMI < 18.5 {
    println("偏瘦")
} elif (18.5 <= BMI) && (BMI < 24) {
    println("正常")
} elif 24 <= BMI && BMI < 28 {
    println("偏胖")
} elif 28 <= BMI && BMI < 30 {
    println("肥胖")
} elif BMI >= 30 {
    println("重度肥胖")
}

pass()

本例中,使用了两类表达式,其中表达式 W / (H * H) 是用于数学计算的表达式,而后面的表达式则都是用于条件判断语句中来表达条件。注意,W / (H * H) 表达式中使用了圆括号来改变了计算的优先级,保证先计算H * H(也就是H2),如果不用圆括号,应该写作等价的 W / H / H。另外,注意第二个条件判断语句中的条件表达式中也使用了圆括号来保证先判断两个子表达式18.5 <= BMI 和 BMI < 24 的条件,然后再进行“逻辑与”操作,但实际上由于“逻辑与”和“逻辑或”操作符的优先级是最低的,所以即使不加上圆括号,整个表达式的计算顺序也是对的,所以后面的条件判断语句就都没有加上圆括号。这点在其他有的语言中是有计算顺序错乱的风险的,因此,如果要和其他语言保持一致,有的开发者还是习惯加上觉得必要的圆括号以保证万无一失,仅省略整个表达式最外层的圆括号即可。

作为用表达式计算和判断体重指数分类的示例,在上一节其实已经做了充分的展示。但是该程序中输入的体重和身高是固定的数值,导致结果也是固定的,作为这样一个具备成为常用工具潜力的程序,值得把它做得更完善一些。下面,我们就介绍如何通过命令行参数来传入不同的体重和身高值来计算体重指数。

命令行参数是在以命令行方式执行程序时,在执行命令中程序名称的后面可以加上的一些参数,一般用于指导程序做一些特定的行为。命令行参数和主程序名称之间用空格分隔开,多个参数之间一般也用空格进行分隔。如果单个参数内部含有空格,则需要将整个参数加上双引号括起来。我们可以在commandLine.gox中输入下面的代码进行测试,

args = os.Args

for i, v = range args {
    pl("命令行参数%v:%v", i, v)
}

for i, v = range argsG {
    pl("精简命令行参数%v:%v", i, v)
}

pass()

输入上面的代码,然后按下面的命令行执行该程序:

gox commandLine.gox abc 123 "How are you!"

可以得到程序的输出结果是:

命令行参数0:gox
命令行参数1:commandLine.gox
命令行参数2:abc
命令行参数3:123
命令行参数4:How are you!
精简命令行参数0:commandLine.gox
精简命令行参数1:abc
精简命令行参数2:123
精简命令行参数3:How are you!

上面的代码中,我们使用了Go语言中标准库中的包“os”,这是一个包含了与操作系统有关的一系列常量、变量和函数的包。其中,os.Args变量是一个os包预定义的变量,它是一个字符串类型的切片变量,在程序运行后这个变量中会包含命令行中的各个参数。之后我们用一个循环来逐个输出os.Args变量中的每一个字符串(args变量已经被赋值为os.Args,所以args与os.Args是等同的,注意切片类型变量的赋值形式)。循环使用了range关键字来遍历args变量,因此i就是遍历过程中的次序序号,v则是args中的每个参数。观察该程序的运行结果可以发现,第一个参数(序号为0)是Gox主程序的名称,第二个参数是脚本文件名称(commandLine.gox),后面则是每一个参数,其中,第4个包含空格字符而用双引号括起来的参数确实被识别成了一个参数,这是符合我们预期的。

而后面用到了Gox语言中内置的全局变量argsG,这个变量相较于os.Args,相当于去掉了第一个命令行参数的精简版。

由于命令执行时,argsG的第一个命令参数就是该脚本文件的文件名,从第二个参数(序号为1)开始仍然是其后所跟的各个命令行参数。

因此,我们取程序运行时的命令行参数只需要从argsG变量序号为1的字符串开始获取即可。下面我们据此来改进计算体重指数的程序:新建一个bmi.gox文件,然后在其中录入下面的代码。

W = toFloat(argsG[1])
H = toFloat(argsG[2])

pl("体重: %.2f", W)
pl("身高: %.2f", H)

BMI = W / (H * H)

pl("BMI: %.2f", BMI)

if BMI < 18.5 {
    pl("偏瘦")
} elif (18.5 <= BMI) && (BMI < 24) {
    pl("正常")
} elif 24 <= BMI && BMI < 28 {
    pl("偏胖")
} elif 28 <= BMI && BMI < 30 {
    pl("肥胖")
} elif BMI >= 30 {
    pl("重度肥胖")
}

这段的代码中,我们通过Gox语言内置的全局变量argsG来获取命令行参数,由于命令行参数是字符串类型,因此还要调用Gox语言内置函数toFloat将其转换为浮点数类型,后面的都与之前的例子中一样了。然后我们用类似下面的命令行来执行该程序(根据脚本文件路径自行调整实际路径名称),

gox bmi.gox 60 1.70

得到的结果是:

体重: 60.00
身高: 1.70
BMI: 20.76
正常

从运行输出结果中可以看出输入的体重和身高被正确识别了。本程序已经可以被用作工具来计算各种体重和身高组合对应的体重指数值并进行分类。如果想要分发该软件给别人用,直接将gox主程序和bmi.gox这个脚本一起拷贝给其他人即可,如果想自动执行,将bmi.gox改名为auto.gox即可。

注意:

  • Gox语言是脱胎于Go语言(Golang)的开源脚本语言,解释执行,但相比Go语言更贴近高级语言,语法硬性限制也少一些;是一门偏向快速应用的语言,也可以说是一个集成工具;

  • Gox语言主要优势有三点:

    • 第一,Gox语言本身只有一个可执行文件,绿色免配置,下载即可使用,无需安装Go语言环境,无需编译,非常适合快速制作原型以及云服务器上的远程开发;
    • 第二,Gox中可以直接使用绝大多数Go语言标准库中的对象和方法函数,也内置了很多常用、优秀的第三方库,充分发挥Go语言多年积累的资源优势;
    • 第三,与很多其他主流语言不同,Gox语言着力解决了GUI图形界面编程的问题,内置了基于Giu(imgui)、LCL、Sciter的三套图形界面编程库,直接可以进行快捷高效的图形界面开发(LCL、Sciter只需分别下载一个动态链接库文件,执行和分发时附带上即可),特别适合编写演示原型系统。

作为脚本语言,Gox语言性能肯定不如Go语言这样的编译型语言快,但由于Gox语言与Go语言的紧密联系,Gox语言编写的脚本可以很容易的改写成Go语言代码,编译执行后就可以发挥Go语言的速度优势了。因此,Gox语言也比较适合做初期的Go语言调试,还有一个更直接的方式是使用Gotx(在Gox官网上也有下载),这是使用完全和Go语言一样语法的解释器,可以理解成集成了Go语言标准库和不少第三方库的解释执行的Go语言,一样也不需要搭建Go语言环境。Gotx与Gox的区别在于,Gotx仍然遵循Go语言的文法,代码相对复杂一些,限制也多一些,但改写回Go语言准备编译执行时,基本上没有成本。

Gox的官网在这里,也可以在浏览器搜索引擎中直接搜索“gox语言”,Github页面在这里,在这里可以看到很多Gox语言的学习指南和实际应用实例。