如何将此示例代码从Go转换为Erlang

时间:2014-10-11 15:01:45

标签: go erlang

我以为我可以一石二鸟并通过将以下示例代码(取自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
    }
}

然而我失败了。代码基本上创建了一个共享计数器(球)并在两个goroutines(球员)之间来回发送。到现在为止还挺好。但是我如何在Erlang中做类似的事情呢?我的问题是:

  • 如何在Erlang中创建计数器? Erlang似乎不允许这样做 设置变量后更改变量的值。
  • 如何在两个erlang进程之间共享这样的计数器?

1 个答案:

答案 0 :(得分:3)

变量在erlang中是不可变的,这意味着在评估一个函数期间,变量要么是未绑定的,要么设置为无法更改的值。但是你可以通过递归方式从前一个值构建一个新的值构建函数。该值存储在通常称为状态的变量中,并在收到消息时进行修改。这是服务器的基本行为。

在你的例子中,你并不需要一个变量来包含计数器,因为这个值将在2个玩家之间进行交换。我可以包含在它们之间交换的消息中,例如在元组{count,V}中。

在两个进程之间进行通信的唯一方法是传递消息。最简单的语法是Pid!消息,其中Pid是接收者的进程ID,消息,以及消息: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>