Luau 是我们的新语言,您可以在https://luau-lang.org 上查阅更多信息。
表格现在已支持 __len 元方法
欲了解详情,请参阅RFC表格支持 __len 元方法及rawlen 功能。
随着5月发布广义迭代,自定义容器比以往任何时候都要更容易操作。唯一的缺点就是表格未顾及__len。
简单地说,现在表格已经支持__len元方法,并且rawlen也以与rawget和rawset类似的语义进行了添加:
local my_cool_container = setmetatable({ items = { 1, 2 } }, {
__len = function (self) return #self.items end
})
print(#my_cool_container) *--> 2*
print(rawlen(my_cool_container)) *--> 0*
never和unknown类型
更多详细信息,请参阅 never 及 unknown 类型 。
我们添加了两种新类型:never 及 unknown。这两种类型是彼此的对立面,因为没有值存在于never类型,而对偶值每个值都存在于unknown类型中。
当且仅当一组可能的类型变为空时(例如,通过类型细化),类型推断便可推断变量具有never类型。
function f (x: string | number)
if typeof(x) == "string" and typeof(x) == "number" then
-- x: never
end
end
这很有用,因为我们仍然需要在此处将类型归属到 x,但我们以前使用的类型具有不正确的语义。例如,一旦用户证明不可能,就有可能扩展变量的域。但如果使用never,缩小never类型范围只会产生never。
相反, unknown可用来强制执行比any更强的契约。也就是说,unknown和any在允许每种类型存在方面是相似的,除了unknown或any之外,any也允许自己存在于不同的类型中,而unknown则不允许。
function any(): any return 5 end
function unknown(): unknown return 5 end
- 无类型错误,但为给 x 分配一个数字,该数字需要字符串
local x: string = any()
- 有类型错误, unknown 无法转换为字符串
local y: string = unknown()
要很好地做到这一点,您必须对unknown类型的变量应用类型细化。
local u = unknown()
if typeof(u) == string then
local y: string = u -- no type error
end
unknown的使用场景是在实施站点对不源自代码但来自网络的数据强制执行类型安全。
MyRemoteEvent.OnServerEvent:Connect( function (player: Player, damage: unknown)
if typeof(damage) == "number" then
-- x: number
end
end )
类型实例化时类型包中的参数名称
在此之前,解析器中有一个bug,错误地允许未折叠到函数类型中的类型包的参数名。也就是说,下面的语法在应该生成解析错误时未生成解析错误。
这个中断更改还尚未启用。我们将联系使用此功能的开发人员,并仅针对工作室启用这个更改。一旦我们知道其使用频率很低的话,我们将在任何地方启用该标示。
Foo<(a: number, b: string)>
新的整数解析 lint
欲了解更多信息,请阅读本公告。
我们引入了一种名为整数解析的新lint。目前包含三类错误:
1.截断解析超过64位的值的二进制文本,
2.截断解析超过64位的值的十六进制文本,以及
3.双十六进制前缀。
1和2目前均未被计划为解析错误,因此此处操作不作严格要求。
但对于3来说,这将会是一个惊人的变化!详见推出计划。
新比较优先级lint
我们还推出了一款名为比较优先级的新lint,会在两种特殊情况下触发:
1.not X op Y,其中 op为 == 或 ~=,或
2. X op Y op Z,其中 op 是任何比较或等式运算符。
在使用!来否定布尔值的语言中,即!x==y看起来不错,因为!x在视觉上比Lua的等效语言(而不是x)绑定得更紧密。可惜的是,这里的优先级是相同的,即!x == y是(!x)== y,与not x == y是(not x)== y相同。我们也将其应用于其它运算符,例如x<=y==y。
- not X==Y 相当于 (not X) == Y ; 考虑使用 X ~= Y ,或将其中一个表达式用括号括起来以保持静默
if not x == y then end
-not X ~= Y 相当于 (not X) ~= Y ; 考虑使用 X == Y ,或将其中一个表达式用括号括起来以保持静默
if not x ~= y then end
-not X <= Y 相当于 (not X) <= Y ; 将其中一个表达式用括号括起来以保持静默
if not x <= y then end
-X <= Y == Z 相当于( X <= Y ) == Z ; 将其中一个表达式用括号括起来以保持静默
if x <= y == 0 then end
有一个特殊例外,对于x == not y 或 not x == not y 等情况,此lint过程不会发出警告,这两种情况在编译时看起来都是有意为之。
返回singleton类型的函数调用错误扩展
修正了一个漏洞,当函数调用返回singleton类型或其类型的合集时,扩展有点太容易触发。这是一种逻辑的产物,知道在毫无意义的情况下不推断singleton类型。
function f (): "abc" | "def"
return if math.random() > 0.5 then "abc" else "def"
end
- 以前报告 “string” 无法转换为 “abc”|“def”*
local x: "abc" | "def" = f()
字符串可以是形状类似于字符串的表格的子类型
函数my_cool_lower是一个函数<a…>(t: t1) → a… ,其中t1 ={+ lower: (t1) → a… +}.
function my_cool_lower (t)
return t:lower()
end
即使t1是表类型,我们知道string是t1的子类型,因为string也有lower,也就是t1的lower的子类型,所以这个调用站点现在进行类型检查。
local s: string = my_cool_lower("HI")
其他分析改进
- string.gmatch/string.match/string.find 现在可以返回更精确的类型,具体取决于所使用的模式
- 修复可能违反类型arena所有权不变量,导致稳定性问题的漏洞
- 修复可能向用户呈现内部类型错误的漏洞
- 使用可选和嵌套表修复假阳性
- 使用广义迭代时,在非严格模式下修复假阳性
- 在某些调用情况下改进自动完成行
- 对于具有元表的类型,修复合成名称中的微小不一致
- 修复没有在光标后建议定义全局变量的自动完成
- 如不推荐使用全局且没有建议的替代选项,修复弃用全局警告文本
- 如string.format使用不正确,请在类型错误文本中修复一个差一错误
其他运行时的改进
- 使用clang作为编译器时,与常量的比较现在要快得多(内部基准的增益为10-50%)
- 在表或字符串上调用不存在的方法时,foo:bar 现在会生成更精确的错误消息
- 提高表的迭代性能
- 使用向量作为表键时,修复向量分量为负零的错误
- 编译器现在可以在-O2下恒定折叠内置,例如string.byte(“A”)编译为常量
- 编译器可以基于内嵌/展开目的模拟内置成本
- 本地重新分配,即 local x = y :: ,如果x及y均未突变/捕获,则T自由
- 根据平台将debug.traceback性能提高1.15-1.75倍
- 当表中不存在键且定义了__newindex时,用表赋值语义修复极端案例: 我们现在使用Lua 5.2语义并调用__newindex,这减少了空间浪费,支持__newindex路径中的NaN密钥以及正确支持冻结表格
- 减少解析器 C 堆栈消耗,从而修复深度嵌套源上的一些堆栈溢出崩溃
- 在隐含宽度情况下提高bit32.extract/replace的性能(faster chess约3%)
- 在字段/宽度为常量的情况下提高 bit32.extract/replace 的性能(faster base64约 10%)
- string.format 现在支持一个新的格式说明符 %*,接受任何值类型并使用字符串规则对其进行格式化
鸣谢
感谢以下所有人的贡献!