「松饼人物编辑器:从入门到欧耶」系列教程(二)

上一讲的习题参考答案

1)

function ondraw()
  print("哈哈")
end

print("呵呵")

2)

function ondraw()
  if who == self then
    print("哈哈")
  else
    print("嘿嘿嘿")
  end
end

print("呵呵")

3) 把 TA 吊起来啪啪啪


变量

为了把人物技能做得明明白白, 学一些 Lua 的基础知识是免不了的。 即使不知道接下来要讲的知识点和人物技能有啥关系, 也要静下心来,慢慢理解 —— 扎实的基础对于理解人物技能而言乃是重中之重。

先看一个例子。 新建人物,名字随便填一个,尬入以下代码:

a = 42
print(a)
a = 233
print(a)

三狗测试,发现依次输出 42 和 233。

这个例子中,a是一个「变量」。 一个变量代表一块内存空间 —— 我们可以向这个空间里写入数据, 也可以从这个空间里读取数据。 下面详细分解一下这四行代码的作用。

  • 第一行的a = 42,就是向a这个变量里写入 42 这个值。 第一行执行结束以后,42 这个值就乖乖躺在a里了。
  • 第二行的print(a)读取并输出了a此时此刻的值 —— 也就是 42。 第二行执行以后,a里的值还是 42 —— 读取并不会改变a
  • 第三行的a = 233,向a这个变量里写入了 233 这个值, 之前的 42 会被覆盖掉 —— 请想象 42 被赶出屋外,而屋子又被 233 占领的景象。 现在a里装着的值已经是 233 了。
  • 于是第四行的print(a)就会输出 233。

向一个变量里写入一个值,叫「赋值」。 表示赋值的符号是=,也就是一个等号。 上面的例子中,我们先后通过=a的值修改成了 42 和 233。

回忆一下,两个等号==用来判断是否相等,别搞混了。

那么问题来了,在我们把 42 存进a以前,a是多少?

试一下不就得了:

print(a)
a = 42
print(a)

三狗测试,发现先后输出 nil 和 42。 也就是说,在我们往a里放 42 以前, anilnil又是个什么鬼?

这不明摆着吗,nil就是啥也没有的意思。 我们没往a里放东西,a里当然啥也没有。

我们可以通过给一个变量赋nil,以达到清空一个变量的目的:

print(a)
a = 42
print(a)
a = nil
print(a)

该代码依次输出 nil, 42, nil


表达式

加减乘除就不用多解释了吧x

a = 3
b = 2
c = a + b * (b - a)
print(c)

每一行代码的作用如下:

  • a = 3,把 3 存进a
  • b = 2,把 2 存进b
  • c = a + b * (b - a),计算a + b * (b - a),将结果存入c
  • print(c) 输出c的值。

赋值号=的右侧可以是个「表达式」。 像 3,2 这种数字都是表达式, 像 a, b 这种变量也是表达式, 像 a + b * (b - a) 这种一长串式子也都是表达式。

表达式是个很强大的东西。 灵活运用表达式,可以让代码变得更简洁。 比如上面的那段代码,也可以这么写:

a = 3
b = 2
print(a + b * (b - a))

我们直接把计算c的表达式写到了print的参数上, 省掉了一行代码。

其实还可以更进一步,把ab也省掉:

print(3 + 2 * (2 - 3))

但这么写有一个缺点:如果你想把a改成 4,怎么办? 只能屁巅屁巅地把所有的 3 都一个个改成 4,不但累,还有可能手滑误改。 但之前的代码就不一样了,直接把a = 3改成a = 4就行了。

写代码的时候要有「防累」和「防手滑」意识。 写下一行代码时,不光要考虑到这行代码是否满足眼下的需要, 更要考虑到将来是否可能会累死、是否可能会手滑。 人不能自己给自己挖坑。

上面的例子中的表达式里用到了括号。 有些时候,即使是不影响计算的优先级,也会多加几个括号 —— 主要是为了确保万无一失,同时也是为了改起来更方便。


变量名

上面的例子里,我们用了a, b, c, d这样的简单变量名。 其实变量名还可以很长:

wwww = 2333
emmmmmmmmmmmmmmmmmmmmmmm = 66666

名字很重要。 变量名起得好,别人一看就能明白这段代码的意思。 反过来,如果a, b, c这种意义不明的名字满天飞, 是会被人吊起来啪啪啪的。

Lua 是区分大小写的:

emmm = 2333
Emmm = 66666
print(emmm)
print(Emmm)

上面的代码输出 2333 和 66666,可见emmmEmmm是两个不同的变量。

变量名可以由字母、数字、和下划线组成,同时不能以数字开头。 虽然可以用大写,但习惯上(至少在 Lua 标准库中)一般只用小写变量名。

在三次元中,你可以给你家的狗起名为if, 但在 Lua 中这是非法的 —— if这个词已经被 Lua 保留了, 它是用来写if语句的,不能再用if给变量命名。 像if这种不能用来给变量命名的词,叫「关键字」。 在 Lua 中,以下单词都是关键字:

and       break     do        else      elseif
end       false     for       function  if
in        local     nil       not       or
repeat    return    then      true      until     while

使用关键字命名变量是非法的。 除此之外,有些变量名虽然合法,但不道德 —— 这就好比三次元中,给小孩起一些奇怪的名字,会影响他们的人生一样。 Lua 中有两种不道德的命名: 一是_G, _ENV这种「下划线开头 + 大写字母」的变量名, 二是__index, __add 这种「双下划线开头」的变量名。 这些名字通常具有一些特殊意义,拿它们给普通的变量命名是作死行为, 鬼才知道会有什么后果。


类型

世上的一切事物都是有类型的。 对于不同类型的事物,我们所能做的事情也不同。

比如,苹果、麻婆豆腐、炸鸡都是「食物」类型的。食物可以吃。 而桌子、椅子、床都是「家具」类型的。家具不能吃,但可以踢。 至于游泳、上吊、捉奸则是属于「行动」类型的。 行动不能吃,不能踢,但可以做。

三次元尚如此,况 Lua 乎? 在 Lua 中,数据一共有 7 种类型:

  • number
  • string
  • boolean
  • table
  • function
  • userdata
  • nil

类型 number

number 就是数字,数字可以用来加减乘除,就好比食物可以吃一样。

我们已经用过好多次数字了,不再赘述:

a = 23333
b = a + 777

类型 string

string 就是字符串。所谓字符串,就是一些文字组成的串。 在 Lua 中,可通过双引号表示字符串:

a = "hahaha"
print(a)

三狗测试,见这段代码输出「hahaha」。

我们可以通过..(两个点)拼接两个字符串:

a = "hahaha"
b = "hehehe"
c = a .. b
print(c)

三狗测试,见这段代码输出「hahahahehehe」。

字符串可以拼接,但不能加减乘除。 这就好比家具可以踢,但不能吃一样。

a = "haha"
b = "hehe"
c = a + b
print(c)

三狗测试,见这段代码报错。

其实有些家具也是可以吃的,比如用麻婆豆腐做成的床就可以吃:

a = "12"
b = "34"
c = a + b
print(c)

上面的代码输出 46。虽然可以正常运行, 但没事别老写这种作死的代码 —— 整天把床当成麻婆豆腐吃,迟早要完。 数字就是数字,字符串就是字符串。

类型 boolean

boolean 只有两种值:truefalse,即真与假。 具体细节以后会详细讲。

a = true
b = false

之前用过的==的计算结果就是 boolean 类型的:

print(1 + 1 == 2)
print(1 + 1 == 3)

测试可知上面的代码先后输出truefalse

类型 table

table 是一种万能的东西, 可以用来做各种数据结构。 至于「数据结构」是个什么鬼,以后再说。

a = { 1, 2, 3, 4, 5 }
b = { width = 200, name = "doge" }
print(a[3])
print(b.name)

类型 function

function 就是函数类型。 这个也以后再详细说吧x

square = function(n)
  return n * n
end

a = square(3)
print(a)

类型 userdata

Lua 这门语言通常用来去「扩展」其它应用。 userdata 就是那些被扩展的应用为 Lua 添加的新类型。 例如,麻将牌、牌山、牌河这此由松饼为 Lua 添加的类型都属于 userdata。

t = T34.new("2m")

类型 nil

之前说过,nil就是什么都没有的意思。 只有nil这个值是 nil 类型的。

我们可以通过== nil来判断一个变量是否为nil

print(a == nil)
a = 2333
print(a == nil)

测试可知,上面的代码先后输出truefalse


练习题

1) 列举两种 Lua 编程中的作死行为
2) 举出一个合法变量名和一个非法变量名的例子
3) 以下代码执行后,a, b, c, d 分别是什么类型?

a = 777
b = "777"
c = d
d = a == b

4) (附加题)上一题的代码执行后,d的值是什么?

下一讲:函数