Factor 的错误系统由三部分组成:用throw发出错误信号,用recover处理错误,以及用ERROR:定义你自己的错误类型。
throwthrow(位于kernel中)会抛出一个错误。它的参数可以是任意值,比如字符串、数字或元组,这个值会成为你之后可以检查的那个错误:
! DOCTEST: SKIP
"file not found" throw
throw不会返回;当前单词的其余部分会被跳过。
recoverrecover(位于continuations中)就是 Factor 的 try/catch。它接受一个 try 引用和一个 recovery 引用:
recover ( try recovery -- )
如果try执行完毕时没有抛出错误,recovery会被忽略。如果try抛出了错误,这个错误会被压入栈中,然后运行recovery:
[ "boom" throw ] [ drop "caught" ] recover .
! => "caught"
[ "ok" ] [ drop "never runs" ] recover .
! => "ok"
来自kernel的when是它的天然搭档:只有当栈顶为真值时,它才会运行一个引用:
: check-positive ( n -- )
0 < [ "negative!" throw ] when ;
ERROR:ERROR:既定义了一个元组类,也定义了一个单词,这个单词会构造一个新实例并把它抛出:
! DOCTEST: SKIP
ERROR: not-found path ;
"/missing" not-found
! throws T{ not-found { path "/missing" } }
不带槽位的错误只需写成ERROR: name ;,调用name会抛出一个空实例。用ERROR:定义的元组会带有一个类谓词name?,你可以用它来判断捕获到的错误是否属于该类型。
捕获到的错误就是一个元组,所以每个ERROR:槽位都带有和其他任何元组相同的、自动生成的slot>>读取器。
! DOCTEST: SKIP
{
T{ not-found { path "/a" } }
T{ not-found { path "/b" } }
}
[ path>> ] map . ! => { "/a" "/b" }
Elena 是一家报纸工厂新来的质量经理,她请你写一小段软件,用来监控生产车间。
使用ERROR:解析词定义一个错误元组类machine-error。它不需要任何槽位。
machine-error ! throws a fresh machine-error
定义check-humidity。它从栈上取一个湿度读数,如果该读数严格大于70,就throws字符串"humidity too high"。否则,不返回任何值。
50 check-humidity ! returns nothing
80 check-humidity ! throws "humidity too high"
定义check-temperature。它取一个温度读数,如果该读数严格大于500,就throws字符串"temperature too high"。否则,不返回任何值。
400 check-temperature ! returns nothing
600 check-temperature ! throws "temperature too high"
定义monitor,让它从栈上取一个湿度和一个温度,并运行这两项检查。如果任意一项检查throws,monitor应该改为抛出一个新的machine-error。如果两项都通过,monitor不返回任何值。
50 400 monitor ! returns nothing
80 400 monitor ! throws a machine-error
50 600 monitor ! throws a machine-error
定义monitor-batch,让它取一个由{ humidity temperature }读数组成的数组,并返回其中有多少个会失败(即有多少个会让monitor抛出异常)。
{ { 50 400 } { 80 400 } { 50 600 } { 60 200 } } monitor-batch .
! => 2