我以为可以用一块石头杀死两只鸟,并通过将以下示例代码(取自http://blog.smartbear.com/programming/an-introduction-to-the-go-language-boldly-going-where-no-man-has-ever-gone-before/)从Go转换为Erlang来教自己一点Go和Erlang:

package main

import (
    "fmt"
    "time"
)

type Ball struct{ hits int }

func main() {
    table := make(chan *Ball)
    go player("ping", table)
    go player("pong", table)
    table <- new(Ball) // game on; toss the ball
    time.Sleep(1 * time.Second)
    <-table // game over; grab the ball
}

func player(name string, table chan *Ball) {
    for {
        ball := <-table
        ball.hits++
        fmt.Println(name, ball.hits)
        time.Sleep(100 * time.Millisecond)
        table <- ball
    }
}

但是我失败了。该代码基本上创建了一个共享的计数器(球),并在两个goroutine(玩家)之间来回发送。到目前为止,一切都很好。但是我该如何在Erlang中做类似的事情?我的问题是:
  • 如何在Erlang中创建一个计数器? Erlang似乎不允许
    设置变量后,更改其值。
  • 如何在两个Erlang进程之间共享这样的计数器?
  • 最佳答案

    变量在erlang中是不可变的,这意味着在评估一个函数期间,该变量未绑定(bind),或者设置为不能更改的值。但是,您可以递归地从前一个函数中调用具有新值构建的相同函数。该值存储在通常称为状态的变量中,并且在收到消息时会对其进行修改。这是服务器的基本行为。

    在您的示例中,您实际上并不需要包含计数器的变量,因为此值将在2个播放器之间交换。我可以包含在它们之间交换的消息中,例如在元组{count,V}中。

    在两个进程之间进行通信的唯一方法是消息传递。最简单的语法是Pid!消息,如果接收者为Pid,则为进程ID;如果为接收者,则为Message,消息为:o)(如果注册了进程,则可以用名称替换Pid)。

    可以这样写:

    -module(pingpong).
    -export([start/0,player/1,stop/1]).
    
    player(Name) ->
        receive
            {count,From,Val} ->
                io:format("~p received the ball for the ~p th exchange~n",[Name,Val]),
                ok = timer:sleep(500),
                From ! {count,self(),Val+1},
                player(Name);
            {start,To} ->
                io:format("~p start the exchange~n",[Name]),
                To ! {count,self(),1},
                player(Name);
             stop -> gameover
         end.
    
    start() ->
        Ping = spawn(?MODULE,player,[ping]),
        Pong = spawn(?MODULE,player,[pong]),
        Ping ! {start,Pong},
        {Ping,Pong}.
    
    stop(P1) -> P1 ! stop.
    

    在 shell 中:
    1> c(pingpong).
    {ok,pingpong}
    2> {P1,P2} = pingpong:start().
    ping start the exchange
    pong received the ball for the 1 th exchange
    {<0.39.0>,<0.40.0>}
    ping received the ball for the 2 th exchange
    pong received the ball for the 3 th exchange
    ping received the ball for the 4 th exchange
    pong received the ball for the 5 th exchange
    ping received the ball for the 6 th exchange
    pong received the ball for the 7 th exchange
    ping received the ball for the 8 th exchange
    pong received the ball for the 9 th exchange
    ping received the ball for the 10 th exchange
    pong received the ball for the 11 th exchange
    ping received the ball for the 12 th exchange
    pong received the ball for the 13 th exchange
    ping received the ball for the 14 th exchange
    pong received the ball for the 15 th exchange
    ping received the ball for the 16 th exchange
    pong received the ball for the 17 th exchange
    ping received the ball for the 18 th exchange
    pong received the ball for the 19 th exchange
    ping received the ball for the 20 th exchange
    pong received the ball for the 21 th exchange
    ping received the ball for the 22 th exchange
    pong received the ball for the 23 th exchange
    ping received the ball for the 24 th exchange
    3> pingpong:stop(P1).
    stop
    4> pingpong:stop(P2).
    stop
    5>
    

    关于go - 如何将此示例代码从Go转换为Erlang,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26316005/

    10-16 08:47