2011-02-10 19 views
6

Per esempio io ho record di Erlang:Erlang elenco di elementi record di

-record(state, {clients 
      }). 

posso fare dalla lista clienti campo?

Che potrei tenere in archivio il cliente come nella lista normale? E come posso aggiungere alcuni valori in questa lista?

Grazie.

risposta

7

Forse vuoi dire qualcosa come:

-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. 

prova:

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()] significa che il tipo di campo è un elenco di valori interi positivi, a partire dal 1; è il suggerimento per lo strumento di analisi dialyzer, quando esegue il controllo dei tipi.

Erlang permette anche di utilizzare il pattern matching sui record:

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

Ulteriori approfondimenti:


@JUST I MIEI OPINION corretti answer mi hanno fatto ricordare che adoro come Haskell va a ottenere i valori dei campi nel tipo di dati.

Ecco una definizione di un tipo di dati, rubato da Learn You a Haskell for Great Good!, che sfrutta la sintassi di registrazione:

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

Si crea funzioni company, model e year, che i campi di ricerca del tipo di dati. Per prima cosa facciamo una nuova auto:

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

Oppure, utilizzando la sintassi di registrazione (l'ordine dei campi non importa):

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 

Possiamo anche usare il pattern matching:

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" 

Ricordo che c'erano tentativi di implementare qualcosa di simile alla sintassi dei record di Haskell in Erlang, ma non sono sicuro che avessero avuto successo.

Alcuni messaggi, relativi a questi tentativi:

Sembra che LFE utilizza le macro, che sono simili a quello che fornisce Scheme (Racket, per esempio), quando si desidera creare un nuovo valore di qualche struttura:

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

Spero che' Avremo qualcosa di simile alla sintassi dei record di Haskell in futuro, che sarebbe davvero praticamente utile e utile.

+0

ewps, è "dializzatore". Altro su Erlang [Records] (http://www.erlang.org/doc/programming_examples/records.html). –

+0

Oh, avrebbe dovuto essere 'clients = [] :: [pos_integer()],' –

+0

Non puoi modificare il tuo post per aggiornarlo con i tuoi 2600 punti di credito? – ndim

1

Se si aggiungono o rimuovono singoli elementi dall'elenco dei clienti nello stato, è possibile ridurre la digitazione con una macro.

-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) }). 

Ecco un test che dimostra 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]). 

Risultato:

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]} 
+1

In questi casi preferisco usare una funzione invece di una macro. Rende il codice più facile da seguire, refactoring e test. –

3

Yasir's answer è quella giusta, ma ho intenzione di mostrarvi perché funziona il modo in cui funziona in modo che tu possa capire i dischi un po 'meglio.

I record in Erlang sono un hack (e uno piuttosto brutto). Usando la definizione record da risposta di Yasir ...

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

... quando si crea un'istanza di questo con #state{} (come fece Yasir in empty_state/0 funzione), ciò che veramente tornare è questa:

{state, [], undefined} 

Vale a dire che il tuo "record" è solo una tupla taggata con il nome del record (state in questo caso) seguito dal contenuto del record. All'interno di BEAM stesso non vi è alcun record. È solo un'altra tupla con i tipi di dati Erlang contenuti al suo interno. Questa è la chiave per capire come funzionano le cose (e le limitazioni dei record da avviare).

Ora, quando Yasser ha fatto questo ...

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

... la punta S#state.clients traduce in codice interno che assomiglia element(2,S). Stai usando, in altre parole, le normali funzioni di manipolazione della tupla. S#state.clients è solo un modo simbolico di dire la stessa cosa, ma in un modo che ti permette di sapere quale elemento 2 in realtà è. La sillabazione sintattica è un miglioramento rispetto alla possibilità di tenere traccia dei singoli campi nelle tuple in modo incline agli errori.

Ora per l'ultimo S#state{clients = [Client|C]} bit, non sono assolutamente positivo su quale codice venga generato dietro le quinte, ma è probabile che sia roba semplice che fa l'equivalente di {state, [Client|C], element(3,S)}. It:

  • tag una nuova tupla con il nome del record (fornito come #state),
  • copie gli elementi da S (dettate dalla porzione S#),
  • fatta eccezione per il clients parte prevalga {clients = [Client|C]}.

Tutta questa magia viene eseguita tramite un processo di pre-elaborazione dietro le quinte.

Capire come i documenti funzionino dietro le quinte è utile sia per capire il codice scritto usando i record sia per capire come usarli da soli (per non parlare del perché le cose che sembrano avere senso) non funzionano con i record - perché in realtà non esistono ancora nella macchina astratta ... ancora).

Problemi correlati