lua基础数据类型
nil
一个变量在第一次赋值前的默认值是 nil, 将nil 赋予给一个全局变量就等同于删除它。
boolean
布尔类型, 可选值 true/false; Lua 中 nil 和 false 为“假”, 其它所有值均为“真”。比如 0 和空
字符串就是“真”;
local a = true
if a then
print("a") -->output:a
else
print("not a") --这个没有执行
end
number
Number 类型用于表示实数。可以使用数学函数 math.floor( 向下取整) 和 math.ceil( 向上取整) 进行取整操作。
local order = 3.99
local score = 98.01
print(math.floor(order)) -->output:3
print(math.ceil(score)) -->output:99
string
Lua 中有三种方式表示字符串:
- 使用一对单引号
'hello'
- 使用一对双引号
"hello"
- 字符串还可以用一种长括号( 即[[ ]]) 括起来的方式定义。
Lua 的字符串是不可改变的值,也不能通过下标来访问字符串的某个字符
local str1 = 'hello world'
local str2 = "hello lua"
local str3 = [["add\name",'hello']]
local str4 = [=[string have a [[]].]=]
print(str1) -->output:hello world
print(str2) -->output:hello lua
print(str3) -->output:"add\name",'hello'
print(str4) -->output:string have a [[]].
table
Table 类型实现了一种抽象的“关联数组”。 “关联数组”是一种具有特殊索引方式的数组, 索引通常是字符串( string) 或者 number 类型, 但也可以是除 nil 以外的任意类型的值。
local corp = {
web = "www.google.com", --索引为字符串, key = "web",
-- value = "www.google.com"
telephone = "12345678", --索引为字符串
staff = {"Jack", "Scott", "Gary"}, --索引为字符串, 值也是一个表
100876, --相当于 [1] = 100876, 此时索引为数字
-- key = 1, value = 100876
100191, --相当于 [2] = 100191, 此时索引为数字
[10] = 360, --直接把数字索引给出
["city"] = "Beijing" --索引为字符串
}
print(corp.web) -->output:www.google.com
print(corp["telephone"]) -->output:12345678
print(corp[2]) -->output:100191
print(corp["city"]) -->output:"Beijing"
print(corp.staff[1]) -->output:Jack
print(corp[10]) -->output:360
function
在 Lua 中, 函数 也是一种数据类型, 函数可以存储在变量中, 可以通过参数传递给其他函数, 还可以作为其他函数的返回值。
local function foo()
print("in the function")
--dosomething()
local x = 10
local y = 20
return x + y
end
local a = foo --把函数赋给变量
print(a())
--output:
in the function
30
表达式
逻辑运算符
逻辑运算符 | 说明 |
---|---|
and | 逻辑与 |
or | 逻辑或 |
not | 逻辑非 |
字符串连接
使用操作符“..”( 两个点)连接两个字符串,也可以使用 string 库函数 string.format 连接字符串。
print("Hello " .. "World") -->打印 Hello World
print(0 .. 1) -->打印 01
str1 = string.format("%s-%s","hello","world")
print(str1) -->打印 hello-world
str2 = string.format("%d-%s-%.2f",123,"world",1.21)
print(str2) -->打印 123-world-1.21
使用table 和 table.concat() 来进行很多字符串的拼接:
local pieces = {}
for i, elem in ipairs(my_list) do
pieces[i] = my_process(elem)
end
local res = table.concat(pieces)
控制结构
if-else
单个if分支
x = 10
if x > 0 then
print("x is a positive number")
end
两个分支if-else
x = 10
if x > 0 then
print("x is a positive number")
else
print("x is a non-positive number")
end
多个分支if-elseif-else
score = 90
if score == 100 then
print("Very good!Your score is 100")
elseif score >= 60 then
print("Congratulations, you have passed it,your score greater or equal to 60")
--此处可以添加多个elseif
else
print("Sorry, you do not pass the exam! ")
end
while
while 表达式 do
--body
end
Lua 并没有像许多其他语言那样提供类似 continue 这样的控制语句用来立即进入下一个循环迭代( 如果有的话) 。 因此, 我们需要仔细地安排循环体里的分支, 以避免这样的需求。
lua提供了break语句,可以跳出当前循环。
repeat
repeat 控制结构类似于其他语言中的 do-while,执行 repeat 循环体后, 直到 until 的条件为真时才结束
x = 10
repeat
print(x)
until false
for
for数字型
for var = begin, finish, step do
--body
end
step参数是可选的,默认为1
for i = 1, 5 do
print(i)
end
for泛型
泛型 for 循环通过一个迭代器( iterator) 函数来遍历所有值:
-- 打印数组a的所有值
local a = {"a", "b", "c", "d"}
for i, v in ipairs(a) do
print("index:", i, " value:", v)
end
-- output:
index: 1 value: a
index: 2 value: b
index: 3 value: c
index: 4 value: d
ipairs()是用于遍历数组的迭代器函数。在每次循环中, i 会被赋予一个索引值, 同时 v 被赋予一个对应于该索引的数组元素值。
pairs()用于遍历
break,return关键字
break
语句 break 用来终止 while 、 repeat 和 for 三种循环的执行, 并跳出当前循环体, 继续执行当前循环之后的语句
return
return 主要用于从函数中返回结果, 或者用于简单的结束一个函数的执行
有时候, 为了调试方便, 我们可以想在某个函数的中间提前 return , 以进行控制流的短路。此时我们可以将 return 放在一个 do ... end 代码块中
local function foo()
print("before")
do return end
print("after") -- 这一行语句永远不会执行到
end
函数的参数
按值传递
Lua 函数的参数大部分是按值传递的。在调用函数的时候,若形参个数和实参个数不同时, Lua会自动调整实参个数。 调整规则:
- 若实参个数大于形参个数, 从左向右, 多余的实参被忽略;
- 若实参个数小于形参个数, 从左向右, 没有被实参初始化的形参会被初始化为 nil。
变长参数
若形参为 ... , 表示该函数可以接收不同长度的参数。 访问参数的时候也要使用 ...
local function func( ... ) -- 形参为 ... ,表示函数采用变长参数
local temp = {...} -- 访问的时候也要使用 ...
local ans = table.concat(temp, " ") -- 使用 table.concat 库函数对数
-- 组内容使用 " " 拼接成字符串。
print(ans)
end
func(1, 2) -- 传递了两个参数
func(1, 2, 3, 4) -- 传递了四个参数
-->output
1 2
1 2 3 4
具名参数
Lua 还支持通过名称来指定实参,这时候要把所有的实参组织到一个 table 中, 并将这个table 作为唯一的实参传给函数
local function change(arg) -- change 函数, 改变长方形的长和宽, 使其各增长一倍
arg.width = arg.width * 2
arg.height = arg.height * 2
return arg
end
local rectangle = { width = 20, height = 15 }
print("before change:", "width =", rectangle.width,
"height =", rectangle.height)
rectangle = change(rectangle)
print("after change:", "width =", rectangle.width,
"height =", rectangle.height)
-->output
before change: width = 20 height = 15
after change: width = 40 height = 30
按引用传递
当函数参数是 table 类型时, 传递进来的是 实际参数的引用, 此时在函数内部对该 table 所做的修改, 会直接对调用者所传递的实际参数生效
function change(arg) --change函数, 改变长方形的长和宽, 使其各增长一倍
arg.width = arg.width * 2 --表arg不是表rectangle的拷贝, 他们是同一个表
arg.height = arg.height * 2
end -- 没有return语句了
local rectangle = { width = 20, height = 15 }
print("before change:", "width = ", rectangle.width,
" height = ", rectangle.height)
change(rectangle)
print("after change:", "width = ", rectangle.width,
" height =", rectangle.height)
--> output
before change: width = 20 height = 15
after change: width = 40 height = 30
函数返回值
函数必须放在调用的代码之前
lua允许函数返回多个值。返回多个值时, 值之间用“,”隔开。
local function swap(a, b) -- 定义函数 swap, 实现两个变量交换值
return b, a -- 按相反顺序返回变量的值
end
模块
一个 Lua 模块的数据结构是用一个 Lua 值( 通常是一个 Lua 表或者 Lua 函数) 。 一个 Lua 模块代码就是一个会返回这个 Lua 值的代码块。可以使用内建函数 require() 来加载和缓存模块。 模块加载后的结果通过是一个 Lua table,这个表就像是一个命名空间,其内容就是模块中导出的所有东西, 比如函数和变量。 require 函数会返回Lua 模块加载后的结果, 即用于表示该 Lua 模块的 Lua 值
require函数
要加载一个模块, 只需要简单地调用 require "file" 就可以了, file 指模块所在的文件名。这个调用会返回一个由模块函数组成的table, 并且还会定义一个包含该 table 的全局变量。
在 Lua 中创建一个模块最简单的方法是: 创建一个 table, 并将所有需要导出的函数放入其中, 最后返回这个 table 就可以了。 相当于将导出的函数作为 table 的一个字段
#my.lua, 创建了my模块
local foo={}
local function getname()
return "Lucy"
end
function foo.greeting()
print("hello " .. getname())
end
return foo
#在main.lua中加载my模块
local fp = require("my")
fp.greeting() -->output: hello Lucy
注: 对于需要导出给外部使用的公共模块, 处于安全考虑, 是要避免全局变量的出现。
String库
string.byte(s[,i[,j]])
返回字符 s[i]、 s[i + 1]、 s[i + 2]、 ······、 s[j] 所对应的 ASCII 码
string.char (...)
接收 0 个或更多的整数( 整数范围: 0~255) , 返回这些整数所对应的 ASCII 码字符组成的字符串
string.upper(s)
接收一个字符串 s, 返回一个把所有小写字母变成大写字母的字符串
string.lower(s)
接收一个字符串 s, 返回一个把所有大写字母变成小写字母的字符串。
string.len(s)
接收一个字符串, 返回它的长度。
string.find(s, p [, init [, plain]])
在 s 字符串中第一次匹配 p 字符串。 若匹配成功, 则返回 p 字符串在 s 字符串中出现的开始位置和结束位置; 若匹配失败, 则返回 nil。
string.format(formatstring, ...)
按照格式化参数 formatstring, 返回后面 ... 内容的格式化版本
string.match(s, p [, init])
在字符串 s 中匹配( 模式) 字符串 p, 若匹配成功, 则返回目标字符串中与模式匹配的子串;否则返回 nil。
string.gmatch(s, p)
返回一个迭代器函数, 通过这个迭代器函数可以遍历到在字符串 s 中出现模式串 p 的所有地方。
string.rep(s, n)
返回字符串 s 的 n 次拷贝。
string.sub(s, i [, j])
返回字符串 s 中, 索引 i 到索引 j 之间的子字符串
string.gsub(s, p, r [, n])
将目标字符串 s 中所有的子串 p 替换成字符串 r
string.reverse (s)
接收一个字符串 s, 返回这个字符串的反转
table库
下标从 1 开始。在 Lua 中, 数组下标从 1 开始计数。
table.getn 获取长度
对于常规的数组, 里面从 1 到 n 放着一些非空的值的时候, 它的长度就精确的为 n, 即最后一个值的下标。 如果数组有一个“空洞”( 就是说, nil 值被夹在非空值之间) , 那么 #t 可能是指向任何一个是 nil 值的前一个位置的下标。
不要在 Lua 的 table 中使用 nil 值, 如果一个元素要删除, 直接 remove, 不要用 nil 去代替。
table.concat (table [, sep [, i [, j ] ] ])
对于元素是 string 或者 number 类型的表 table, 返回 table[i]..sep..table[i+1] ··· sep..table[j] 连接成的字符串
table.insert (table, [pos ,] value)
在( 数组型) 表 table 的 pos 索引位置插入 value, 其它元素向后移动到空的地方
table.maxn (table)
返回( 数组型) 表 table 的最大索引编号; 如果此表没有正的索引编号, 返回 0
table.remove (table [, pos])
在表 table 中删除索引为 pos( pos 只能是 number 型) 的元素, 并返回这个被删除的元素,它后面所有元素的索引值都会减一
table.sort (table [, comp])
按照给定的比较函数 comp 给表 table 排序, 也就是从 table[1] 到 table[n], 这里 n 表示 table的长度
日期时间函数
os.time ([table])
如果不使用参数 table 调用 time 函数, 它会返回当前的时间和日期( 它表示从某一时刻到现在的秒数)
os.difftime (t2, t1)
返回 t1 到 t2 的时间差, 单位为秒
os.date ([format [, time]])
把一个表示日期和时间的数值, 转换成更高级的表现形式
格式字符 | 含义 |
---|---|
%a | 一星期中天数的简写( 例如: Wed) |
%A | 一星期中天数的全称( 例如: Wednesday) |
%b | 月份的简写( 例如: Sep) |
%B | 月份的全称( 例如: September) |
%c | 日期和时间( 例如: 07/30/15 16:57:24) |
%d | 一个月中的第几天[01 ~ 31] |
%H | 24小时制中的小时数[00 ~ 23] |
%I | 12小时制中的小时数[01 ~ 12] |
%j | 一年中的第几天[001 ~ 366] |
%M | 分钟数[00 ~ 59] |
%m | 月份数[01 ~ 12] |
%p | “上午( am) ”或“下午( pm) ” |
%S | 秒数[00 ~ 59] |
%w | 一星期中的第几天[1 ~ 7 = 星期天 ~ 星期六] |
%x | 日期( 例如: 07/30/15) |
%X | 时间( 例如: 16:57:24) |
%y | 两位数的年份[00 ~ 99] |
%Y | 完整的年份( 例如: 2015) |
%% | 字符'%' |
数学库
函数名 | 函数功能 |
---|---|
math.rad(x) | 角度x转换成弧度 |
math.deg(x) | 弧度x转换成角度 |
math.max(x, ...) | 返回参数中值最大的那个数, 参数必须是number型 |
math.min(x, ...) | 返回参数中值最小的那个数, 参数必须是number型 |
math.random ([m[, n]]) | 不传入参数时, 返回 一个在区间[0,1)内均匀分布的伪随机实数; 只使用一个整数参数m时, 返回一个在区间[1, m]内均匀分布的伪随机整数; 使用两个整数参数时, 返回一个在区间[m, n]内均匀分布的伪随机整数 |
math.randomseed(x) | 为伪随机数生成器设置一个种子x, 相同的种子将会生成相同的数字序列 |
math.abs(x) | 返回x的绝对值 |
math.fmod(x, y) | 返回 x对y取余数 |
math.pow(x, y) | 返回x的y次方 |
math.sqrt(x) | 返回x的算术平方根 |
math.exp(x) | 返回自然数e的x次方 |
math.log(x) | 返回x的自然对数 |
math.log10(x) | 返回以10为底, x的对数 |
math.floor(x) | 返回最大且不大于x的整数 |
math.ceil(x) | 返回最小且不小于x的整数 |
math.pi | 圆周率 |
math.sin(x) | 求弧度x的正弦值 |
math.cos(x) | 求弧度x的余弦值 |
math.tan(x) | 求弧度x的正切值 |
math.asin(x) | 求x的反正弦值 |
math.acos(x) | 求x的反余弦值 |
math.atan(x) | 求x的反正切值 |
文件操作
io.open (filename [, mode])
按指定的模式 mode, 打开一个文件名为 filename 的文件, 成功则返回文件句柄, 失败则返回 nil 加错误信息
模式 | 含义 | 文件不存在时 |
---|---|---|
"r" | 读模式 (默认) | 返回nil加错误信息 |
"w" | 写模式 | 创建文件 |
"a" | 添加模式 | 创建文件 |
"r+" | 更新模式, 保存之前的数据 | 返回nil加错误信息 |
"w+" | 更新模式, 清除之前的数据 | 创建文件 |
"a+" | 添加更新模式, 保存之前的数据,在文件尾进行添加 | 创建文件 |
file:close ()
关闭文件。 注意: 当文件句柄被垃圾收集后, 文件将自动关闭。 句柄将变为一个不可预知的值。
io.close ([file])
关闭文件, 和 file:close() 的作用相同。 没有参数 file 时, 关闭默认输出文件。
file:flush ()
把写入缓冲区的所有数据写入到文件 file 中。
io.flush ()
相当于 file:flush(), 把写入缓冲区的所有数据写入到默认输出文件
io.input ([file])
当使用一个文件名调用时, 打开这个文件( 以文本模式) , 并设置文件句柄为默认输入文件; 当使用一个文件句柄调用时, 设置此文件句柄为默认输入文件; 当不使用参数调用时,返回默认输入文件句柄。
file:lines ()
返回一个迭代函数, 每次调用将获得文件中的一行内容, 当到文件尾时, 将返回 nil, 但不关闭文件。
io.lines ([filename])
打开指定的文件 filename 为读模式并返回一个迭代函数, 每次调用将获得文件中的一行内容,当到文件尾时, 将返回 nil, 并自动关闭文件。 若不带参数时 io.lines() 等价于 io.input():lines()读取默认输入设备的内容, 结束时不关闭文件。
io.output ([file])
类似于 io.input, 但操作在默认输出文件上。
file:read (...)
按指定的格式读取一个文件。 按每个格式将返回一个字符串或数字, 如果不能正确读取将返回nil, 若没有指定格式将指默认按行方式进行读取。
格式 | 含义 |
---|---|
"*n" | 读取一个数字 |
"*a" | 从当前位置读取整个文件。 若当前位置为文件尾, 则返回空字符串 |
"*l" | 读取下一行的内容。 若为文件尾, 则返回nil。 (默认) |
number | 读取指定字节数的字符。 若为文件尾, 则返回nil。 如果number为0,则返回空字符串, 若为文件尾,则返回nil |
io.read (...)
相当于 io.input():read
io.type (obj)
检测 obj 是否一个可用的文件句柄。 如果 obj 是一个打开的文件句柄, 则返回 "file" 如果 obj是一个已关闭的文件句柄, 则返回 "closed file" 如果 obj 不是一个文件句柄, 则返回 nil。
file:write (...)
把每一个参数的值写入文件。 参数必须为字符串或数字, 若要输出其它值, 则需通过 tostring 或 string.format 进行转换。
io.write (...)
相当于 io.output():write
file:seek ([whence] [, offset])
设置和获取当前文件位置, 成功则返回最终的文件位置(按字节, 相对于文件开头),失败则返回 nil 加错误信息。
whence | 含义 |
---|---|
"set" | 文件开始 |
"cur" | 文件当前位置(默认) |
"end" | 文件结束 |
file:setvbuf (mode [, size])
设置输出文件的缓冲模式
模式 | 含义 |
---|---|
"no" | 没有缓冲, 即直接输出 |
"full" | 全缓冲, 即当缓冲满后才进行输出操作(也可调用flush马上输出) |
"line" | 以行为单位, 进行输出 |
元表
元表 (metatable) 的表现行为类似于 C++ 语言中的操作符重载
Lua 提供了两个十分重要的用来处理元表的方法, 如下:
- setmetatable(table, metatable): 此方法用于为一个表设置元表。
- getmetatable(table): 此方法用于获取表的元表对象。
# 设置元表
local mytable = {}
local mymetatable = {}
setmetatable(mytable, mymetatable)
元方法 | 含义 |
---|---|
"__add" | + 操作 |
"__sub" | - 操作 其行为类似于 "add" 操作 |
"__mul" | * 操作 其行为类似于 "add" 操作 |
"__div" | / 操作 其行为类似于 "add" 操作 |
"__mod" | % 操作 其行为类似于 "add" 操作 |
"__pow" | ^ ( 幂) 操作 其行为类似于 "add" 操作 |
"__unm" | 一元 - 操作 |
"__concat" | .. ( 字符串连接) 操作 |
"__len" | # 操作 |
"__eq" | == 操作 函数 getcomphandler 定义了 Lua 怎样选择一个处理器来作比较操作 仅在两个对象类型相同且有对应操作相同的元方法时才起效 |
"__lt" | < 操作 |
"__le" | <= 操作 |
"__index" | 取下标操作用于访问 table[key] |
"__newindex" | 赋值给指定下标 table[key] = value |
"__tostring" | 转换成字符串 |
"__call" | 当 Lua 调用一个值时调用 |
"__mode" | 用于弱表(week table) |
"__metatable" | 用于保护metatable不被访问 |
面向对象
类
可以使用表和函数实现面向对象。 将函数和相关的数据放置于同一个表中就形成了一个对象。
下面的代码,创建了account类: account.lua
local _M = {}
local mt = { __index = _M }
function _M.deposit (self, v)
self.balance = self.balance + v
end
function _M.withdraw (self, v)
if self.balance > v then
self.balance = self.balance - v
else
error("insufficient funds")
end
end
function _M.new (self, balance)
balance = balance or 0
return setmetatable({balance = balance}, mt)
end
return _M
下面代码是使用account类示例:
local account = require("account")
local a = account:new()
a:deposit(100)
local b = account:new()
b:deposit(50)
print(a.balance) --> output: 100
print(b.balance) --> output: 50
继承
继承可以用元表实现, 它提供了在父类中查找存在的方法和变量的机制。 在 Lua 中是不推荐使用继承方式完成构造的, 这样做引入的问题可能比解决的问题要多
---------- s_base.lua
local _M = {}
local mt = { __index = _M }
function _M.upper (s)
return string.upper(s)
end
return _M
---------- s_more.lua
local s_base = require("s_base")
local _M = {}
_M = setmetatable(_M, { __index = s_base })
function _M.lower (s)
return string.lower(s)
end
return _M
---------- test.lua
local s_more = require("s_more")
print(s_more.upper("Hello")) -- output: HELLO
print(s_more.lower("Hello")) -- output: hello
局部变量
在一个 block 中的变量, 如果之前没有定义过, 那么认为它是一个全局变量, 而不是这个 block 的局部变量
Lua 中的局部变量要用 local 关键字来显式定义, 不使用 local 显式定义的变量就是全局变量
局部变量的生命周期是有限的, 它的作用域仅限于声明它的块( block) 。 一个块是一个控制结构的执行体、 或者是一个函数的执行体再或者是一个程序块( chunk)
“尽量使用局部变量”是一种良好的编程风格
判断数组大小
table.getn(t) 等价于 #t 但计算的是数组元素, 不包括 hash 键值。 而且数组是以第一个 nil 元素来判断数组结束。 # 只计算 array 的元素个数, 它实际上调用了对象的 metatable 的__len 函数。 对于有 __len 方法的函数返回函数返回值, 不然就返回数组成员数目。
注意: 一定不要使用 # 操作符或 table.getn 来计算包含 nil 的数组长度, 这是一个未定义的操作, 不一定报错, 但不能保证结果如你所想。 如果你要删除一个数组中的元素, 请使用remove 函数, 而不是用 nil 赋值。
非空判断
对于table型变量,可以如下判断非空:
local person = {name = "Bob", sex = "M"}
if person ~= nil and person.name ~= nil then
print(person.name)
end
对于简单类型的变量, 我们可以用 if (var == nil) then 这样的简单句子来判断。 但是对于 table型的 Lua 对象, 就不能这么简单判断它是否为空了。 一个 table 型变量的值可能是 {} , 这时它不等于 nil
正则表达式(openresty中的正则表达式规范 -- ngx.re.*)
下面是使用openresty中正则的例子:
location /test {
content_by_lua_block {
local regex = [[\d+]]
-- 参数 "j" 启用 JIT 编译, 参数 "o" 是开启缓存必须的
local m = ngx.re.match("hello, 1234", regex, "jo")
if m then
ngx.say(m[0])
else
ngx.say("not matched!")
end
}
}
正则中使用了jo 两个参数:
- ngx.re.* 中的 o 选项, 指明该参数, 被编译的 Pattern 将会在工作进程中缓存, 并且被当前工作进程的每次请求所共享
- ngx.re.* 中的 j 选项, 指明该参数, 如果使用的 PCRE 库支持 JIT, OpenResty 会在编译 Pattern 时启用 JIT。即使运行在不支持 JIT 的 OpenResty 上, 加上 j 选项也不会带来坏的影响
lua正则汇总:
符号 | 匹配次数 | 匹配模式 |
---|---|---|
+ | 匹配前一字符 1 次或多次 | 非贪婪 |
* | 匹配前一字符 0 次或多次 | 贪婪 |
- | 匹配前一字符 0 次或多次 | 非贪婪 |
? | 匹配前一字符 0 次或1次 | 仅用于此, 不用于标识是否贪婪 |
符号 | 匹配模式 |
---|---|
. | 任意字符 |
%a | 字母 |
%c | 控制字符 |
%d | 数字 |
%l | 小写字母 |
%p | 标点字符 |
%s | 空白符 |
%u | 大写字母 |
%w | 字母和数字 |
%x | 十六进制数字 |
%z | 代表 0 的字符 |
虚变量
当一个方法返回多个值时, 有些返回值有时候用不到, 要是声明很多变量来一一接收, 显然不太合适( 不是不能) 。 Lua 提供了一个虚变量(dummy variable), 以单个下划线( “_”) 来命名, 用它来丢弃不需要的数值, 仅仅起到占位的作用。
-- string.find (s,p) 从string 变量s的开头向后匹配 string
-- p, 若匹配不成功, 返回nil, 若匹配成功, 返回第一次匹配成功的起止下标。
local start, finish = string.find("hello", "he") --start 值为起始下标, finish
--值为结束下标
print ( start, finish ) --输出 1 2
local start = string.find("hello", "he") -- start值为起始下标
print ( start ) -- 输出 1
local _,finish = string.find("hello", "he") --采用虚变量( 即下划线) , 接收起
--始下标值, 然后丢弃, finish接收
--结束下标值
print ( finish ) --输出 2
点号与冒号操作符的区别
冒号操作会带入一个 self 参数, 用来代表 自己 。 而点号操作, 只是 内容 的展开。
local str = "abcde"
print("case 1:", str:sub(1, 2))
print("case 2:", str.sub(str, 1, 2))