如何创建抑制错误和警告的宏?
How to create a macro that suppresses errors and warnings?
我想重新定义或覆盖 Base
中的一些函数,而不让用户注意到这一点。我前段时间发现了这个技巧:
original_stderr = STDERR
redirect_stderr()
# code
redirect_stderr(original_stderr)
这对我来说成了一个重复的模式,所以我做了一个宏:
macro suppress_err(block)
quote
orig_err = STDERR
redirect_stderr()
val = $block
redirect_stderr(orig_err)
val
end
end
但它从未像预期的那样运行(即使没有宏):
- jl_uv_writecb() 错误:windows() 上的管道 EPIPE 损坏
- REPL: jl_uv_writecb() 破管 EPIPE
在Windows中:
julia> @suppress_err warn()
julia> @suppress_err error()
ERROR:
in error at error.jl:22
Windows Linux 的子系统:
julia> @suppress_err warn()
[1] 17 abort (core dumped) julia
julia 7.69s user 2.36s system 106% cpu 9.441 total
在Linux中:
julia> @suppress_err +(x, y) = x - y
ERROR: UndefVarError: #11#x not defined
in eval(::Module, ::Any) at ./boot.jl:234
in macro expansion at ./REPL.jl:92 [inlined]
in (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at ./event.jl:46
显然我做错了一些事情,我应该如何处理这个问题?我应该在 Julia 存储库中提出问题吗?
我也尝试在两个 err_rd, err_wr = redirect_stderr()
上使用 close
,然后再次重定向到原始 STDERR
,但没有成功。
更新:
我用我所做的制作了一个 Suppressor 包,这样您就可以轻松地对其进行测试:
Pkg.clone("https://github.com/Ismael-VC/Suppressor.jl")
所有的宏都有相同的基本形式:
macro suppress_err(block)
quote
let
if ccall(:jl_generating_output, Cint, ()) == 0
ORIGINAL_STDERR = STDERR
err_rd, err_wr = redirect_stderr()
value = $(esc(block))
REDIRECTED_STDERR = STDERR
redirect_stderr(ORIGINAL_STDERR)
# This doesn't help:
# close(err_rd)
# close(err_wr)
return value
end
end
end
end
- 我添加了来自
JuliaParser
here 的安全检查
您需要保留对原始 redirect_stderr
的 return 值的引用。它return既是读端又是写端,但是写端存储在STDERR
中,读端不是,所以GC可能会决定去掉它。如果发生这种情况,它会在系统级别关闭,因此当 julia 尝试写入它时,它会收到该错误。
注意:下面的示例代码根据当前 Suppressor.jl
版本更新。
macro suppress_err(block)
quote
if ccall(:jl_generating_output, Cint, ()) == 0
ORIGINAL_STDERR = STDERR
err_rd, err_wr = redirect_stderr()
err_reader = @async readstring(err_rd)
value = $(esc(block))
redirect_stderr(ORIGINAL_STDERR)
close(err_wr)
return value
end
end
end
我想重新定义或覆盖 Base
中的一些函数,而不让用户注意到这一点。我前段时间发现了这个技巧:
original_stderr = STDERR
redirect_stderr()
# code
redirect_stderr(original_stderr)
这对我来说成了一个重复的模式,所以我做了一个宏:
macro suppress_err(block)
quote
orig_err = STDERR
redirect_stderr()
val = $block
redirect_stderr(orig_err)
val
end
end
但它从未像预期的那样运行(即使没有宏):
- jl_uv_writecb() 错误:windows() 上的管道 EPIPE 损坏
- REPL: jl_uv_writecb() 破管 EPIPE
在Windows中:
julia> @suppress_err warn()
julia> @suppress_err error()
ERROR:
in error at error.jl:22
Windows Linux 的子系统:
julia> @suppress_err warn()
[1] 17 abort (core dumped) julia
julia 7.69s user 2.36s system 106% cpu 9.441 total
在Linux中:
julia> @suppress_err +(x, y) = x - y
ERROR: UndefVarError: #11#x not defined
in eval(::Module, ::Any) at ./boot.jl:234
in macro expansion at ./REPL.jl:92 [inlined]
in (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at ./event.jl:46
显然我做错了一些事情,我应该如何处理这个问题?我应该在 Julia 存储库中提出问题吗?
我也尝试在两个 err_rd, err_wr = redirect_stderr()
上使用 close
,然后再次重定向到原始 STDERR
,但没有成功。
更新:
我用我所做的制作了一个 Suppressor 包,这样您就可以轻松地对其进行测试:
Pkg.clone("https://github.com/Ismael-VC/Suppressor.jl")
所有的宏都有相同的基本形式:
macro suppress_err(block)
quote
let
if ccall(:jl_generating_output, Cint, ()) == 0
ORIGINAL_STDERR = STDERR
err_rd, err_wr = redirect_stderr()
value = $(esc(block))
REDIRECTED_STDERR = STDERR
redirect_stderr(ORIGINAL_STDERR)
# This doesn't help:
# close(err_rd)
# close(err_wr)
return value
end
end
end
end
- 我添加了来自
JuliaParser
here 的安全检查
您需要保留对原始 redirect_stderr
的 return 值的引用。它return既是读端又是写端,但是写端存储在STDERR
中,读端不是,所以GC可能会决定去掉它。如果发生这种情况,它会在系统级别关闭,因此当 julia 尝试写入它时,它会收到该错误。
注意:下面的示例代码根据当前 Suppressor.jl
版本更新。
macro suppress_err(block)
quote
if ccall(:jl_generating_output, Cint, ()) == 0
ORIGINAL_STDERR = STDERR
err_rd, err_wr = redirect_stderr()
err_reader = @async readstring(err_rd)
value = $(esc(block))
redirect_stderr(ORIGINAL_STDERR)
close(err_wr)
return value
end
end
end