Erlang记录项目列表

时间:2011-02-10 05:40:38

标签: list erlang record

例如我有erlang记录:

-record(state, {clients
            }).

我可以从客户字段列表制作吗?

我可以保留在正常列表中的客户端吗?如何在此列表中添加一些值?

谢谢。

3 个答案:

答案 0 :(得分:7)

也许你的意思是:

-module(reclist).
-export([empty_state/0, some_state/0, 
         add_client/1, del_client/1,
         get_clients/1]).

-record(state, 
     {    
          clients = []   ::[pos_integer()],
          dbname         ::char()
     }).    

empty_state() ->
     #state{}.

some_state() ->
     #state{
          clients = [1,2,3],
          dbname  = "QA"}.

del_client(Client) ->
     S = some_state(),
     C = S#state.clients,
     S#state{clients = lists:delete(Client, C)}. 

add_client(Client) ->
     S = some_state(),
     C = S#state.clients,
     S#state{clients = [Client|C]}.

get_clients(#state{clients = C, dbname = _D}) ->
     C.

测试:

1> reclist:empty_state().
{state,[],undefined}
2> reclist:some_state(). 
{state,[1,2,3],"QA"}
3> reclist:add_client(4).
{state,[4,1,2,3],"QA"}
4> reclist:del_client(2).
{state,[1,3],"QA"}

::[pos_integer()]表示字段的类型是正整数值列表,从1开始;它是分析工具dialyzer的提示,当它执行类型检查时。

Erlang还允许您在记录上使用模式匹配:

5> reclist:get_clients(reclist:some_state()).
[1,2,3]

进一步阅读:


@JUST MY正确的OPINION answer让我记得我喜欢Haskell如何获取数据类型中字段的值。

以下是从Learn You a Haskell for Great Good!窃取的数据类型的定义,它利用了记录语法:

data Car = Car {company :: String 
               ,model   :: String
               ,year    :: Int
               } deriving (Show)

它创建了函数companymodelyear,它们是数据类型中的查找字段。我们先制作一辆新车:

ghci> Car "Toyota" "Supra" 2005
Car {company = "Toyota", model = "Supra", year = 2005}

或者,使用记录语法(字段的顺序无关紧要):

ghci> Car {model = "Supra", year = 2005, company = "Toyota"}
Car {company = "Toyota", model = "Supra", year = 2005}
ghci> let supra = Car {model = "Supra", year = 2005, company = "Toyota"}
ghci> year supra
2005

我们甚至可以使用模式匹配:

ghci> let (Car {company = c, model = m, year = y}) = supra
ghci> "This " ++ c ++ " " ++ m ++ " was made in " ++ show y
"This Toyota Supra was made in 2005"

我记得曾尝试在Erlang中实现类似于Haskell的记录语法,但不确定它们是否成功。

有关这些尝试的一些帖子:

当您想要创建某个结构的新值时,似乎LFE使用的宏类似于提供Scheme(Racket)的宏:

> (define-struct car (company model year))
> (define supra (make-car "Toyota" "Supra" 2005))
> (car-model supra)
"Supra"

我希望将来我们会有一些接近Haskell记录语法的东西,这实际上非常实用且方便。

答案 1 :(得分:3)

Yasir's answer是正确的,但我会告诉你为什么它的工作方式有效,所以你可以更好地理解记录。

Erlang中的记录是一个黑客(而且非常难看)。使用Yasir答案的记录定义......

-record(state, 
     {    
          clients = []   ::[pos_integer()],
          dbname         ::char()
     }).

...当你用#state{}实例化时(正如Yasir在empty_state/0函数中所做的那样),你真正得到的是:

{state, [], undefined}

也就是说,您的“记录”只是一个标记有记录名称(在本例中为state)的元组,后跟记录的内容。在BEAM内部没有记录。它只是包含Erlang数据类型的另一个元组。这是理解工作原理(以及启动记录的限制)的关键。

现在当Yasir做到这一点......

add_client(Client) ->
     S = some_state(),
     C = S#state.clients,
     S#state{clients = [Client|C]}.

... S#state.clients位转换为内部代码,看起来像element(2,S)。换句话说,您正在使用标准元组操作函数。 S#state.clients只是表达同一事物的象征性方式,但在某种程度上让您知道实际上 的元素2是什么。这是一种语法糖精,它比以容易出错的方式跟踪元组中的各个字段有所改进。

现在对于最后一个S#state{clients = [Client|C]}位,我对于幕后生成的代码并不是绝对肯定的,但它可能只是简单的东西,相当于{state, [Client|C], element(3,S)}。它:

  • 使用记录名称(提供为#state),
  • 标记新元组
  • 复制S的元素(由S#部分决定),
  • clients覆盖的{clients = [Client|C]}件外。

所有这些魔法都是通过幕后的预处理黑客完成的。

了解记录如何在幕后工作对于理解使用记录编写的代码以及理解如何自己使用它们都是有益的(更不用说理解为什么似乎“有意义”的东西不能用于记录 - - 因为它们实际上并不存在于抽象机器中......但是)。

答案 2 :(得分:1)

如果您只是在州内的客户列表中添加或删除单个项目,则可以减少使用宏键入内容。

-record(state, {clients = [] }).

-define(AddClientToState(Client,State),
    State#state{clients = lists:append([Client], State#state.clients) } ).

-define(RemoveClientFromState(Client,State),
    State#state{clients = lists:delete(Client, State#state.clients) } ).

这是一个测试escript,用于演示:

#!/usr/bin/env escript

-record(state, {clients = [] }).

-define(AddClientToState(Client,State),
    State#state{clients = lists:append([Client], State#state.clients)}  ).

-define(RemoveClientFromState(Client,State),
    State#state{clients = lists:delete(Client, State#state.clients)}    ).  


main(_) ->

    %Start with a state with a empty list of clients.
    State0 = #state{},
    io:format("Empty State: ~p~n",[State0]),

    %Add foo to the list
    State1 = ?AddClientToState(foo,State0),
    io:format("State after adding foo: ~p~n",[State1]),

    %Add bar to the list.
    State2 = ?AddClientToState(bar,State1),
    io:format("State after adding bar:  ~p~n",[State2]),

    %Add baz to the list.
    State3 = ?AddClientToState(baz,State2),
    io:format("State after adding baz:  ~p~n",[State3]),

    %Remove bar from the list.
    State4 = ?RemoveClientFromState(bar,State3),
    io:format("State after removing bar:  ~p~n",[State4]).

结果:

Empty State: {state,[]}
State after adding foo: {state,[foo]}
State after adding bar:  {state,[bar,foo]}
State after adding baz:  {state,[baz,bar,foo]}
State after removing bar:  {state,[baz,foo]}