Erlang:变量'结果'不安全的尝试'

时间:2015-07-22 13:04:10

标签: syntax compiler-construction scope erlang try-catch

我正在使用Erlang R16B03。

此代码:

list_dir(Directory, Retries) when is_integer(Retries), Retries > 0 ->
    Port = get_efile_port(),
    try erlang:port_info(Port) of
        Result ->
            error_logger:info_msg("list_dir - erlang:port_info(~p) ->  ~p ", [Port,Result])
    catch
        _:Reason ->
             error_logger:info_msg("list_dir - erlang:port_info(~p) -> {error, ~p }",[Port,Reason])
    end,
    case prim_file:list_dir(Port, Directory) of
        {error, einval} ->
            error_logger:info_msg(" list_dir -  port : ~p , directory : ~p", [Port, Directory]),
            clear_efile_port(),
            list_dir(Directory, Retries-1);
        Result ->
            Result
    end.

生成以下编译器异常:

/basho/riak/deps/bitcask/src/bitcask_fileops.erl:855: variable 'Result' unsafe in 'try' (line 843)
ERROR: compile failed while processing /basho/riak/deps/bitcask: rebar_abort
make: *** [compile] Error 1

但是,如果我将变量名Result的第一次使用重命名为Res,它编译得很好,例如:

list_dir(Directory, Retries) when is_integer(Retries), Retries > 0 ->
    Port = get_efile_port(),
    try erlang:port_info(Port) of
        Res ->
            error_logger:info_msg("list_dir - erlang:port_info(~p) ->  ~p ", [Port,Res])
    catch
        _:Reason ->
             error_logger:info_msg("list_dir - erlang:port_info(~p) -> {error, ~p }",[Port,Reason])
    end,
    case prim_file:list_dir(Port, Directory) of
        {error, einval} ->
            error_logger:info_msg(" list_dir -  port : ~p , directory : ~p", [Port, Directory]),
            clear_efile_port(),
            list_dir(Directory, Retries-1);
        Result ->
            Result
    end.

据我所知,变量在两个不同的范围内(try / catch和case)。

这是编译错误还是我没能正确理解Erlang语法?

3 个答案:

答案 0 :(得分:7)

这不是编译器错误。问题在于,在第一个示例中,您在两个位置使用Result:首先在try中,然后再在case中。这些不是两个不同的范围,而是相同的范围。编译器抱怨,因为如果try中没有引发异常,Result将绑定erlang:port_info(Port)调用的结果,但如果该调用引发异常,{{1}不受约束。这意味着它在Result中的使用将是不明确的,因为在第二个case子句中,如果它已经绑定将匹配,或者如果它尚未绑定则绑定到case的结果

答案 1 :(得分:3)

try块本身返回一个值。所以你可以避免这样的情况

list_dir(Directory, Retries) when is_integer(Retries), Retries > 0 ->
    Port = get_efile_port(),
    Result = try erlang:port_info(Port) of
          ... 

例如,这里是我正在进行的项目中的几行:

F = try
      python:call(P, 'python.repo_admin_cmd', 'repo_admin_cmd', [erlang:list_to_binary(Command) || Command <- Commands])
catch error:{python, _Class, _Argument, _StackTrace} ->
     error
end

如果我要尝试分配&#34; F&#34;在&#34;尝试&#34;我得到了同样的错误!

答案 2 :(得分:2)

由于您已与Result子句匹配,因此结果将绑定到值。其范围不受限制。请考虑以下代码:

#! /usr/bin/env escript

main([What]) ->
    case What of
        Value when Value == "hello" ->
            Result = foo(Value),
            ok; 
        Value when Value == "goodbye" ->
            Result = foo(Value),
            ok  
    end,
    io:format("~p ~p",[Result, Value]).

foo("hello") ->
    "ohai";

foo("goodbye") ->
    "cya".

即使Value仅限于case子句,它仍可在外部范围内访问。请注意同样的事情,Result变量也包含在case子句中。