编写脚本时应该注意的一个问题

我最近在看一些网友写的脚本时,发现有存在一个共同的问题:

脚本有出错的可能

出错的原因不是程序设计本身的问题,而是没有考虑到用户的操作可能不会按照作者的意图去进行。一个完善的脚本是必须要考虑到各种意外情况的,毕竟如果脚本在运行的弹出错误信息,或者带界面的脚本直接崩溃,这都会带来很差的体验。

我写脚本的时候,经常考虑的一个问题是:**如果用户是一个专门捣蛋的人,我怎么能保证脚本无论什么情况下都不会出错或崩溃?**比如,如果脚本需要先画出time selection,而对方偏不画?如果脚本需要对选中的item进行处理,而对方偏不选?如果你要对方输入一个数字,而对方输入了文字?

你的脚本能不能在不满足必要条件的时候不出错?

这是写脚本的时候,除了主要功能以外,必须考虑的一个点,你必须无死角的堵住每个会导致你出错的漏洞。最常用的方法就是,如果必要条件不满足,停止运行:

if XXX then return end

例1 获取选中item的名字

local it=reaper.GetSelectedMediaItem(0, 0)
local tk=reaper.GetActiveTake(it)
local name=reaper.GetTakeName(tk)
reaper.ShowConsoleMsg(name)

正常来说,这些代码能显示出选中item的名字,但这里埋了两个坑在里面。如果没有选中item就运行,就会得到出错信息:

bad argument #1 to 'GetActiveTake' (MediaItem expected)

因为没有选中item,所以第一行获得的就是个空值,因此在第二行想要获取take的时候报错。因此得先加一个判断,如果没有选中item的话脚本提前结束

if reaper.CountSelectedMediaItems(0)==0 then return end  --没有选中item的情况
local it=reaper.GetSelectedMediaItem(0, 0)
local tk=reaper.GetActiveTake(it)
local name=reaper.GetTakeName(tk)
reaper.ShowConsoleMsg(name)

第二个坑在于第三行,如果选中的是一个empty item,因为empty item没有take,因此获取到的也是一个空值,导致第四行会出错

bad argument #1 to 'GetTakeName' (MediaItem_Take expected)

所以要对获取到的take加一个判断是否空值,是的话提前结束

if reaper.CountSelectedMediaItems(0)==0 then return end  --没有选中item的情况
local it=reaper.GetSelectedMediaItem(0, 0)
local tk=reaper.GetActiveTake(it)
if not tk then return end  --判断是否empty item
local name=reaper.GetTakeName(tk)
reaper.ShowConsoleMsg(name)

这样下来,可以保证无论对方如何操作,都不会有出错的可能

例2 获取用户输入内容

一般用这个函数来获取

local check, text=reaper.GetUserInputs('title', 1, 'content', '')

当用到这个函数,首先应该考虑:如果用户点了取消或者关掉窗口怎么办?函数第一个返回值就是检测这个的,点取消或者关掉窗口,第一个返回值(check)会是false,因此下一步应该先做判断:

local check, text=reaper.GetUserInputs('title', 1, 'content', '')
if not check then return end  --检测是否正常输入

然后如果用户给你捣蛋,输入窗口是空的,然后点了确定。这时变量check是true,输入值text将是一个空字符串’’,因此再多加一个判断:

local check, text=reaper.GetUserInputs('title', 1, 'content', '')
if not check or text=='' then return end  --检测是否正常输入

这样最大程度避免了获得不正常输入而导致后面出错的可能。但这还是初步的,还要根据程序具体的设计,使用 string.match 函数来判断一下这个获取到的数值是否符合要求的格式

1 个赞

确实如此,应对各种奇葩操作都要有对应的动作,要么静默,要么提示输入错误。

我给自己写东西的时候喜欢用assert,某一步错误了就直接不执行到底。或许偷懒也可以这样做,不知道有没有什么坏处。

比较庆幸一开始学的是涉及游戏对象的 RGSS(Ruby 的阉割版),对边界都会有比较明确的规范,于是把这个好习惯也一直保留了下来。
说起来,REAPER 自带的插件(以及 JS 插件)也有这种问题,例如输入框的数值其实是可以超出范围的,于是我做的插件也做了一些手段来规避这类问题发生。

2 个赞

学习了,谢谢Z神!