Erlang:'try'中变量'Result'不安全

bry*_*unt 7 compiler-construction syntax erlang scope 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.
Run Code Online (Sandbox Code Playgroud)

生成以下编译器异常:

/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
Run Code Online (Sandbox Code Playgroud)

但是,如果我重新命名了第一次使用的变量名ResultRes,它编译罚款,如:

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.
Run Code Online (Sandbox Code Playgroud)

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

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

Ste*_*ski 8

这不是编译器错误.问题是在第一个例子中,你Result在两个地方使用:第一个在try,然后再在case.这些不是两个不同的范围,而是相同的范围.编译器抱怨,因为如果没有引发异常try,Result将绑定到erlang:port_info(Port)调用的结果,但如果该调用引发异常,Result则不会被绑定.这意味着它在内部的使用case将是不明确的,因为在第二case个子句中,如果它已经绑定,它将匹配,或者如果它尚未绑定则绑定到结果prim_file:list_dir(Port, Directory).


Via*_*lev 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".
Run Code Online (Sandbox Code Playgroud)

即使Value仅在子句中绑定case,它仍然可以在外部范围中访问。请注意,Result变量也有界于 case 子句。