- 论坛徽章:
- 5
|
本帖最后由 starwing83 于 2012-11-19 06:27 编辑
OwnWaterloo 发表于 2012-11-19 00:07 ![]()
我就是还没来得及写啊。。。 你这到底是要我这就写还是等会写。。。 就现在写吧。。。
C++,Java(Clojure),C#,Python,Elisp,CL,Scheme,它们 —— 或者只说Python之前的那些,因为后面那些的non local jump各有各的不同,也不自称为异常 —— 的异常是可以一路走到底的。
发现错误的点抛异常。 想处理错误的点写try/catch。 不想处理错误的点写try/finally或者析构或者with。 不需要进行exception <-> status code的转换。
C++得单独算, 如果不考虑编译器兼容, 也是可以一路走到底。
C++如果考虑编译器兼容, 就要在编译边界进行 exception <-> status code 的转换。 边界之中, 异常也是可以走到底。
而lua。。。 转换粒度比C++还小是闹哪样。。。
这一个帖子的中心思想就这一个,我就这一起回了。
接前面所说的三个目的(实现手法我就不提了,前贴有):
1. 状态码转异常
2. 异常转状态码
3. finally
首先必须说明的是,我发现你一直没搞明白一点,Lua的异常本身是可以一路走到底的,因为newtry本身在捕获以后会自动rethrow。所以本质上是一路走到底。在“一路走到底”上,单纯newtry足矣。
即,newtry完全等价于C++的析构,或者Python的with。
如果想catch,就写异常转换状态码,如果想throw,就写状态码转换异常。即assert = throw;protect = try/catch,newtry = try/finially。请问还缺啥?
举一个小例子好了:- local socket = require 'socket'
- local newtry, protect = socket.newtry, socket.protect
- local function no_throw_error()
- return nil, "no_throw error!"
- end
- local function throw_error()
- error "throw error!"
- end
- local function f(n, throw)
- if n ~= 1 then -- 模拟多次调用
- f(n-1, throw)
- return "OK"
- end
- -- 我们假设要释放点什么
- try = newtry(function()
- print(debug.traceback "collected!")
- end)
- if throw then
- -- 扔错误的函数,用pcall包裹
- try(pcall(throw_error))
- else
- -- 不扔错误的函数,直接调用
- try(no_throw_error())
- end
- -- 注意,try会rethrow
- end
- print "test 1"
- -- 用protect调用
- local res, errmsg = protect(f)(10, "throw")
- if not res then
- print("error in f: ", errmsg)
- -- 如果你愿意,error(errmsg)就是rethrow
- end
- print(res, errmsg)
- print "test 2"
- -- 用pcall调用
- local res, errmsg = pcall(f, 10, not "throw")
- if not res then
- print("error in f: ", errmsg[1])
- end
- print(res, errmsg)
复制代码 执行的结果是
lua -- "noname\2012-11-19-1.lua"
test 1
collected!
stack traceback:
noname\2012-11-19-1.lua:19: in function <noname\2012-11-19-1.lua:18>
[C]: in function 'try'
noname\2012-11-19-1.lua:23: in function 'f'
noname\2012-11-19-1.lua:14: in function 'f'
noname\2012-11-19-1.lua:14: in function 'f'
noname\2012-11-19-1.lua:14: in function 'f'
noname\2012-11-19-1.lua:14: in function 'f'
noname\2012-11-19-1.lua:14: in function 'f'
noname\2012-11-19-1.lua:14: in function 'f'
noname\2012-11-19-1.lua:14: in function 'f'
noname\2012-11-19-1.lua:14: in function 'f'
noname\2012-11-19-1.lua:14: in function <noname\2012-11-19-1.lua:12>
[C]: in ?
noname\2012-11-19-1.lua:33: in main chunk
[C]: in ?
error in f: noname\2012-11-19-1.lua:9: throw error!
nil noname\2012-11-19-1.lua:9: throw error!
test 2
collected!
stack traceback:
noname\2012-11-19-1.lua:19: in function <noname\2012-11-19-1.lua:18>
[C]: in function 'try'
noname\2012-11-19-1.lua:26: in function 'f'
noname\2012-11-19-1.lua:14: in function 'f'
noname\2012-11-19-1.lua:14: in function 'f'
noname\2012-11-19-1.lua:14: in function 'f'
noname\2012-11-19-1.lua:14: in function 'f'
noname\2012-11-19-1.lua:14: in function 'f'
noname\2012-11-19-1.lua:14: in function 'f'
noname\2012-11-19-1.lua:14: in function 'f'
noname\2012-11-19-1.lua:14: in function 'f'
noname\2012-11-19-1.lua:14: in function <noname\2012-11-19-1.lua:12>
[C]: in function 'pcall'
noname\2012-11-19-1.lua:42: in main chunk
[C]: in ?
error in f: no_throw error!
false table: 0056CF50
Hit any key to close this window...
注意一个问题,每层中间,如果需要收异常,就protect,不需要,就放着扔,try本身就保证了东西会被回收。异常是可以一把扔到底的。中间有人protect了,可以error { errmsg } 重新扔;中间try了,会自动重新扔,即使是每次有异常/状态码转换,你也看不见。我想问问你:对于一门异常不是官方支持的语言来说,除了状态码,你还有什么别的办法能执行catch块????难道用函数?这里用函数很浪费好不好!而且你看到了,你根本看不到状态码的转换!
newtry(function()
print "这里写catch代码"
end)(f)
local err, msg = protect(f)(...) -- 或者pcall(f, ...)
print "这里写finially代码"
-- rethrow? error { msg }
就这么简单。
|
|