【问题标题】:Erlang "badarg", Not sure how to handleErlang“badarg”,不知道如何处理
【发布时间】:2016-10-26 17:42:54
【问题描述】:

在开始之前,我已经签出了Handle badarg in Erlang 但是我的未定义检查仍然没有成功,所以我删除了它们。

我正在构建一个虚拟银行进程,当客户对银行进程进行余额查询检查时,程序退出,说:

Error in process <0.373.0> with exit value:
{badarg,[{project4,client,3,
                   [{file,"/Users/owner/Desktop/bank.erl"},
                    {line,27}]}]}

=ERROR REPORT==== 26-Oct-2016::13:34:57 ===
Error in process <0.379.0> with exit value:
{badarg,[{project4,client,3,
                   [{file,"/Users/owner/Desktop/bank.erl"},
                    {line,27}]}]}

=ERROR REPORT==== 26-Oct-2016::13:34:57 ===
Error in process <0.375.0> with exit value:
{badarg,[{project4,client,3,
                   [{file,"/Users/owner/Desktop/bank.erl"},
                    {line,27}]}]}

=ERROR REPORT==== 26-Oct-2016::13:34:58 ===
Error in process <0.377.0> with exit value:
{badarg,[{project4,client,3,
                   [{file,"/Users/owner/Desktop/bank.erl"},
                    {line,27}]}]}
<0.378.0> Balance request: 54> 
=ERROR REPORT==== 26-Oct-2016::13:34:58 ===
Error in process <0.378.0> with exit value:
{badarg,[{project4,client,3,
                   [{file,"/Users/owner/Desktop/bank.erl"},
                    {line,39}]}]}
<0.372.0> Balance request: 54> 
=ERROR REPORT==== 26-Oct-2016::13:34:58 ===
Error in process <0.372.0> with exit value:
{badarg,[{project4,client,3,
                   [{file,"/Users/owner/Desktop/bank.erl"},
                    {line,39}]}]}

模拟的代码在这里:

-module(bankSim).
-export([start/0, negativeOrPositive/0, sleep/1, generate_rand_int_list/3, generate_rand/2, client/3, clientSpawn/2, bank/2]).

negativeOrPositive() -> 
    M = rand:uniform(),
    if
        M =< 0.5 -> 
            1;
        true -> 
            -1
    end.

sleep(T) ->
    receive
        after T -> ok
    end.

generate_rand_int_list(N,StartVal,Lim) ->
    lists:map(fun (_) -> (rand:uniform(Lim-StartVal) + StartVal)* negativeOrPositive() end, lists:seq(1,N)).

generate_rand(StartVal, Lim) ->
    rand:uniform(Lim-StartVal) + StartVal.

client([], _ , BankID) ->
    BankID ! {goodbye};
client([H|T], Count, BankID) ->
    BankID ! {transaction, self(), H},
    receive
        {Amount, Balance, Success} ->
            io:format("Client: ~w, Amount requested: ~w, Bank Balance: ~w, Transaction successful ~w ~n",[self(), Amount, Balance, Success]);
        { X } ->
            io:format("The balance is ~w ~n", [X])
    end,    
    sleep(generate_rand(500, 1500)),
    Mod = Count rem 5,
    if 
        Mod == 0 -> 
            io:format("~w Balance request: ",[ self() ]),
            BankID! {balance, self()};
        true -> 
            ok
    end,
    client(T, Count + 1, BankID).

clientSpawn(0, _) ->
        io:format("Finished spawning clients ~n",[]);
clientSpawn(N, BankID) -> 
        spawn(bankSim, client, [ generate_rand_int_list( generate_rand(10, 20), 0, 100) , 1, BankID] ),
        clientSpawn(N-1, BankID).


bank(Balance, 0) ->
    io:format("Banking simulation ended with a final balance of ~w ~n", [Balance]),
    io:format("simulation completed ~n", []);
bank(Balance, NumClients) ->
    receive
        {balance, Client} ->
            Client ! {Balance};
        {transaction, Client, Amount} ->
            NewBalance = Balance + Amount,
            if 
                NewBalance =< 0 ->
                    Client ! {Amount, NewBalance, no},
                    bank(Balance, NumClients);
                NewBalance > 0 ->
                    Client ! {Amount, NewBalance, yes},
                    bank(NewBalance, NumClients);
                true -> 
                    io:format("This will never be printed")
            end;
        goodbye ->
            NewNumClients = NumClients - 1,
            bank(Balance, NewNumClients)
    end.


start()->
    N = generate_rand(2,10),
    register(bank ,spawn(bankSim, bank, [generate_rand(2000,3000), N])),
    clientSpawn(N,bank).

任何帮助将不胜感激。

【问题讨论】:

  • 您好像忘记了对 {balance, Client} 消息的递归调用? (第 57-58 行。)
  • 这似乎奏效了,我盯着它看了这么久,我可能一直在掩饰这样一个简单的错误。

标签: erlang


【解决方案1】:

Erlang 文档会告诉你 badarg 表示 "The argument is of wrong data type, or is otherwise badly formed." 我从来没有发现很清楚。

Dogbert 指出,在您的一个案例中,您错过了对 bank/2 的递归调用。这是您的badargs 的来源——但为什么呢?

我一直认为badarg 的意思是“发送到 BIF 的错误参数”。如果您正在调用常规 Erlang 函数,您将收到 function_clause 错误,这意味着没有与您的数据匹配的函数子句。

您收到的错误消息列出了两个不同的行号。一个是为了线

BankID ! {transaction, self(), H},

另一个为

BankID! {balance, self()};

错误的参数是BankID。它不好的原因是因为它是一个原子,bank。在您的start/0 函数中,您生成一个新的银行进程,然后将该进程的PID 注册为bank。然后在您的客户端中,您将消息发送到 bank 原子并让 Erlang 将其解析为注册的 PID。

它可以工作一段时间,但是当您遇到缺少回收的情况时,您的bank 进程将终止。现在bank 原子后面没有人注册,发送操作符因为无法发送到已失效的名称而崩溃。

如果您将代码更改为

Bank = spawn(bankSim, bank, [generate_rand(2000,3000), N]),
clientSpawn(N, Bank).

那么您将不会收到badarg,因为将消息发送到无人运行的 PID 并不是错误。您可能会喜欢在不修复 bank 循环并查看会发生什么的情况下尝试这样做。

【讨论】:

  • 由于您的解释,我将其标记为正确,并且您提供的解决方案也是正确的。感谢您的洞察力!
  • @Nathaniel,关于句子I always think of badarg as meaning "bad argument sent to a BIF"To ! Msg 的注释是对运算符send 的调用,它使用两个参数,尽管Erlang 创建者选择了运算符语法来发送消息,但与global:send(To,Msg) 语法相比,差别不大。非常简洁的答案。
  • 您还会发现,在某些标准库中,如果参数错误,您也会收到badarg 错误。这是明确完成的,因为它绝对比function_clause 错误或case_clause 或由于错误参数而可能发生的其他错误提供更多信息。
猜你喜欢
  • 2014-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-26
  • 2016-11-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多