Lua表达式

  • 算术操作符
  • 关系操作符
  • 逻辑操作符
  • 字符串连接
  • 优先级
  • 表构造式

算术运算符

Lua支持常规的算术操作符,算术操作符用于实数。

+ 二元加法
- 二元减法 取负
* 乘法
/ 除法
^ 指数求幂
% 求模取余

指数求幂

x = 4
print(x^0 .5) --计算平方根 2.0
x = 8
print(x^(1/3)) --计算立方根 2.0
print(x^(-1/3)) --计算立方根的倒数 0.5

求模取余

求模取余计算规则:a%b = a - floor(a/b)*b,对于整数来说计算结果的符号永远与第二个参数相同,对于实数则由其他用途。

x = math.pi
print(x%1, x-x%1, x-x%0.01)  -- 0.14159265358979     3.0    3.14
--[[ 
x%1 计算结果是x的小数部分
x-x%1 计算结果是x的整数部分
x-x%0.01 精确到小数点后两位
--]]

假设一辆车是否在旋转了一定角度后开始往回开,假如旋转角以角度给出。

local to_lerance = 10
function isTurnBack(angle)
    angle = angle%360
    return (math.abs(angle-180) < to_lerance)
end

print(isTurnBack(-180)) -- true

若以弧度代替角度

local to_lerance = 0.17
function isTurnBack(angle)
    angle = angle%(math.pi*2)
    return (math.abs(angle-math.pi)

关系运算符

< 大于
> 小于
>= 大于等于
<= 小于等于
~= 不等于

print(2>1 and 3>2) -- true
print(1>2 and 1<2) -- false
print(1<2 and 3) -- 3
print("521".."1314") -- 5211314

Lua提供的关系操作符包括< > <= >= == ~=,其运算结果都是truefalse

== 用于相等性测试,~= 用于不等性测试,可应用于任意两个值。若两个值具有不同类型,Lua就认为他们是不相等的。否则,Lua会根据他们的类型来比较。注意nil只与自身相等。

对于tableuserdatafunction,Lua是做引用比较的。也就是说,只有当他们引用同一个对象时,才认为他们相等。

user = {}; 
user.age = 20; 
user.weight = 80
person = {}; 
person.age = 20; 
person.weight = 80
human = user
print( user == human, user ~= person) -- true true
  • 只能对两个数字或字符串做大小比较
  • Lua按字母次序(alphabetical order)比较字符串,具体的字母次序取决于对Lua的区域设置。
  • 对两个不同类型的值比较时,要格外小心。
  • 为避免类型不一致的比较,Lua会在遇到字符串和数字的大小比较时引发一个错误。
print("0"==0) -- false
print("2"<"15") -- false
print(2<"15") -- attempt to compare number with string

逻辑运算符

  • and
    当两个表达式都为真时结果为真
    若第一个表达式为真,第二个表达式为非布尔型的值,则输出此值。
  • or
    当两个表达式其一为真,则结果为真。
    若第一个表达式为false,第二个表达式为非布尔值,则输出此值。
  • not
    取反运算,即布尔值取反。
    不是false和nil的值都表示true

逻辑操作符有and or not,与条件控制语句一样,所有逻辑操作符将false nil视为假,其他都视为真。

  • 对于and来说,如果第一个操作数为假,则返回第一个操作数,否则返回第二个操作数。
print(1 and 2) -- 2
print(nil and 1) -- nil
print(false and 1) -- false
  • 对于or来说,如果第一个操作数为真,则返回第一个操作数,否则返回第二个操作数。
print(1 or 2) -- 1
print(nil or 1) -- 1
print(false or 1) -- 1

andor都使用“短路求值(short-cut evaluation)”,也就是说,它们只会在需要时才去评估第二个操作数。短路求值可确保(type(v)=='table' and v.tag=='h1')这样的表达式不会导致运行时错误。

常用的Lua习惯写法x = x or v,它等价于if not x then x=v end

它可用在设置x的时候,即对x的求值结果为假时,将其设置为一个默认值。

常用Lua习惯写法(a and b) or c,类似于C语言中的表达式a?b:c,但前提是b不为假。

-- 选出数字x和y中的较大者
max = (x>y) and x or y

--[[
若x>y则and的第一个操作数为真,那么and运算结果就是第二个操作数x。
而x是一个永远为真的表达式,因为x是一个数字。
同理,or运算的结果就是第一个操作数x。
当x>y为假的时候,and表达式为假,因此or的结果就是第二个操作数y。
--]]

操作符not永远返回的只是truefalse

print(not 0)  -- false
print(not 1)  -- false
print(not nil)  -- true
print(not true)  -- false
print(not false)  -- true

字符串连接

..连接符号为两个点,用于连接两个字符串。

Lua中连接两个字符串,可使用操作符..,如果其中任意一个操作数是数字的话,Lua将会自动将数字转为字符串。

print("hello " .. "world") -- hello world
print(0 .. 1) -- 01

Lua中的字符串是不可变的值(immutable value),连接操作符只会创建一个新的字符串,而不会对原操作数做任何修改。

str = "hello "
print(str .. "world") -- hello world
print(str) -- hello

优先级

Lua操作符的优先级

^
not # -
* / %
+ -
..
< > <= >= == ~=
and
or

在二元操作符中,除了指数求幂^和连接符..是右结合外,其他操作符都是左结合(left associative)。

a+i < b/2+1
( a + i ) < ( ( b / 2 ) + 1 )
5 + x ^ 2 * 8
5 + ( ( x ^ 2 ) * 8 )
 a
(x ^ 2)
 x^y^z
x ^ ( y ^ z )

表构造式

表的构造,构造器是创建和初始化表的表达式,表是Lua特有的功能强大的数据类型,最简单的构造函数是{},用来创建空表。

local tbl = {}

表构造式(table constructor)用于创建和初始化table的表达式,这是Lua特有的一种表达式,并且也是Lua中最有用、最通用的机制之一。

构造式可用于初始化数组

days = {"sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"}
print(days[1], days[2], days[3], days[#days])
-- sunday   monday  tuesday saturday

Lua提供特殊语法用于创建记录风格的table

user = { name = "alice", age = 20 }

-- 等价代码
user = {}
user.name = "alice"
user.age = 20

无论采用哪种方式创建table,都可以在table创建后添加或删除其中的字段。

user = { name = "alice", age = 20,  male = true }
user[1] = "admin"
print( user["name"], user[1] ) -- alice admin

user.name = nil
print(user["name"]) -- nil

所有的table都可以构建成一样的,而构造式只是在table的初始化时刻才发挥作用。

每当调用构造式时,会先创建一个新的table,然后初始化它。这样,就能用table构建链表结构list

list = nil
for line in io.lines() do
    list = { next = list, value = line }
end
--[[
从标准输入读取每行内容,将每行按相反的次序存储到链表中。
链表中每个节点都有一个`table`,`table`中含有两个字段,`value`为每行的内容,`next`为指向下个节点的引用。
--]]
local l = list
while l do
    print(l.value)
    l = l.next
end
--[[
Lua程序很少使用链表,列表数据常用数组来实现。
--]]

将记录风格的初始化和列表风格的初始化混合在一个构造式中使用

polyline = {
    color = "red",
    thickness = 2,
    npoint = 4,
    {x = 0, y = 0},
    {x = -10, y = 0}
}
print(polyline[2].x) --10

--[[
通过嵌套的构造式表示复杂的数据结构
--]]

两种风格的构造式各有限制

不能使用负数的索引,不能使用运算符作为记录的字段名。为了满足这些要求,Lua提供了更为通用的格式。格式允许在方括号之间,显式地用一个表达式来初始化索引值。

opnames = {
    ["+"] = "add",
    ["-"] = "sub",
    ["*"] = "mul",
    ["/"] = "div",
}

local str = "-"
print(opnames[str]) -- sub

无论是列表分隔的初始化,还是记录风格初始化,其实都是使用通用语法特例。

如果想要数组下标从0开始,可手工指定索引:

days = {
  [0] = "Sunday",
  "Monday",
  "Tuesday",
  "Wednesday",
  "Thursday",
  "Friday",
  "Saturday"
}

不推荐数组下标从0开始,否则很多标准库不能使用。

某些情况如果以0作为数组的起始索引的话,不推荐在Lua中作为数组的其实索引。大多数内建函数都假设起始于索引1,若遇到以索引0开始的数组,它们就无法正确地处理了。

这种灵活性对于那些Lua table的程序而言,它们无需将最后一个元素作为特例处理。

在构造函数“域分隔符”逗号,可用分号;替代,使用发呢好用来风格不同类型的表元素。

{
  x = 10,
  y = 10;
  "username",
  "password"
}

你可能感兴趣的:(Lua表达式)