record and macro

Record

1. A record is a data structure with a fixed number of fields that can be accessed by name. Records are different from tuples, whose fields can be accessed by location information. A record type can be defined as follows:

-record(person,{name,age,phone}).

This introduces the record type person, where each record instance contains three named fields: name, age, and phone. Field names are defined as primitives. The following is an example of a record of this type:

#person{

name="Joe",

age=21,

phone="999-999"

}

It is also possible to provide default values ​​for fields in the definition of the record:

-record(person,{name,age=0,phone=""}).

If no default value is given, "default default" is the primitive undefined.

2. The general definition of a name record containing fields from field1 to fieldn takes the following format:

-record(name,filed1[=default1],

        filed2[=default2],

 ...

 filedn[=defaultn])

Parts in square brackets are declarations of optional field default values, the same field name can be used for more than one record type, and in fact, two records can share the same list of names. The name of the record can only be used for a definition, it is used to identify the record anyway.

Operation record

1.Person=#person{name="Fred"}

The fields of the record can be read like this: Person#person.name, Person#person.age, etc.

2. The general form of accessing a field is:

RecordExp#name.fieldName

where name and fieldName cannot be variables, and RecordExp is an expression used to indicate that this is a record, usually this is a variable, but it could also be the result of an application function or a field access to another record type.

3. Suppose you need to modify a field of a record, you can write it directly like this:

NewPerson=Person#person{age=37}.

In this case the real advantage of the record syntax comes in, just mention the fields whose values ​​need to be changed, those fields whose values ​​do not change from Person to NewPerson do not need to be specified in the definition. In fact, the logging mechanism allows updating any select field, for example:

NewPerson=Person#person{phone="999-999",age=37}

4. The general format of the modified record field is:

RecordExp#name{...,fieldNamei=valuei,...}

Field updates can occur in any order, but each field name can occur at most once.

Record-based function and pattern matching

1. Record-based pattern matching can extract field values ​​and affect the control flow of calculations. Suppose you want to define a birthday function to increase the age of this person by 1, you can use field selection, and then update the definition of this function:

birthday(P)->

P#person{age=P#person.age+1}

It would obviously be simpler and clearer to use pattern matching:

birthday(#person{age=Age}=P)->

P#person{age=Age+1}

2. Record fields can contain any valid Erlang data type, because records are valid data types, so fields can also contain other records, which results in nested records. For example, in a person record, the content of the name field could itself be a record:

-record(name,{first,surname})

P=#person{name=#name{first="Rebort",surname="Virding"}}

First=(P#person.name)#name.first

record in terminal

1. Records in Erlang are only valid in the compiler, they do not have their types in the virtual machine. Because of this, the terminal treats them differently than other constructs.

2. In the terminal, you can use the command rr(moduleName) to load all the record definitions in the module moduleName, or you can use the command rd(name,{field1,field2,...}) in the terminal to directly define the definitions that contain field1 , field2, etc. name records. This is useful for testing and debugging, or when you don't have access to a module where the record definition resides. Finally, use the command rl() to list all record definitions currently visible in the terminal.

3. Finally, the terminal commands rf(RecordName) and rf() delete one or all record definitions currently visible in the terminal.

record implementation

1. The Erlang compiler makes the record valid before the program runs, converts the record into a tuple, and converts the functions that belong to the record into functions and built-in functions that belong to the corresponding tuple.

2. The tuple representation of records should not be used: Because using this data form breaks the data abstraction, any changes you make to the record type will not be reflected in the code when using tuples. If you add a field to the record, the size of the tuple created by the compiler will change, causing a badmatch error when trying to pattern match the record to the tuple. If records are being used, swapping the order of fields in the record won't affect the code, because accessing fields by name, and then using tuples in places and forgetting to swap all the specific values, the program may run wrong or worse , the program may exhibit unexpected behavior.

3. If you want to view the generated code of the records during code conversion, please use the "E" option when compiling the module. The result will generate a file with the suffix of E. Let's take the compilation records1 as an example: use compile:file(records1 ,['E']) or the terminal command c(records1,['E']) will generate a file named records1.E, the beam file containing the object code is not generated.

Document built-in functions

1. The built-in function record_info provides us with a record type and the information it represents. The function call record_info(fields, recType) returns a list of field names in recType, and the function call record_info(size, recType) returns the size of the tuple, which is the number of fields plus 1. The position of a field in the tuple is determined by #recType.fieldName, and both recType and fieldName are primitives.

2. The built-in functions record_info/2 and #RecordType.Field calculations can contain no variables, but must contain literal primitives, this is because they are processed by the compiler before the code runs and the variables are bound, they will be converted first is the expressed value.

3. A built-in function that can be used in a guard element is is_record(Term, RecordTerm). This built-in function will verify that the item element is a tuple, its first element is a RecordTag, and that the size of the tuple is correct, this built-in function returns the primitive true or false.

macro

1. Macros allow you to use structure abbreviations in Erlang, and Erlang's preprocessor (EPP) will expand them at compile time. Macros can make programs more readable and implement features outside the language itself. Using conditional macros, it is possible to write programs that can be customized in different ways, switching between debug and production modes or between different system architectures.

simple macro

1. The simplest macro can be used to define a constant, such as:

-define(TIMEOUT,1000)

Macros are created by placing a ? in front of the macro's name? to use, such as:

receive

after ?TIMEOUT->ok

end.

2. The general form of a simple macro definition is:

-define(Name,Replacement).

Capitalizing Names is customary, but not required. In fact, it can be any sequence of Erlang tokens, that is, it can be a sequence of words, such as variables, primitives, symbols or punctuation marks. The result is not necessarily a complete Erlang expression or top-level form (ie, a function definition or pragma). It is not possible to generate new keywords through macro expansion.

Macro parameterization

1. Macros can have parameters identified by variable names. The general form of a macro with parameters is:

-define(Name(Var1,Var2,...,Varn),Replacement)

Here, as normal Erlang variables, the variables Var1, Var2, ..., Varn need to capitalize the first letter.

2. Another example of macro parameterization is for diagnostic printouts, it is not uncommon to have two macros defined in the code, and it is not uncommon to comment out one of them. When developing the system, debug and print all the information in the code. When you want to turn it off, all you need to do is comment out one part of the definition and uncomment the other part of the definition before recompiling the code.

Debugging and Macros

1. One of the main uses of macros in Erlang is to allow code to be introduced in different ways. The advantage of the macro method is that conditional macros can be used, which can generate different versions of the code, such as debug builds and production builds.

2. In the first aspect, macros have the ability to retain the parameters of the macro as a string, which consists of parameter markers, which can be achieved by prefixing the variable with ??, for example:

-define(VALUE(Call),io:format("~p=~p~n",[??Call,Call]))

test1()->VALUE(length([1,2,3])).

The first use of the Call parameter is ??Call, which will expand to text as a string parameter, and the second use will continue to expand in the terminal.

3. On the second side, there is a set of predefined macros that are commonly used in debugging code.

?MODULE: expands to the name of the module it is in

?MODULE_STRING: a string that expands to the name of the module it is in

?FILE: expands to the filename where it resides

?LINE: expands to the line number it is on

?MACHINE: The virtual machine used by the extension, so far the only possible value is BEAM.

4. Finally, it is possible to define conditional macros that expand in different ways depending on the different flags passed to the compiler.

-undef(Flag): reset Flag

-ifdef(Flag): If Flag is set, the following statement is executed.

-ifndef(Flag): If no Flag is set, the next statement will be executed.

-else: This provides another possibility, if this condition is met, the next statement will be executed.

-elseif: Terminate conditional constructs.

Here is an example of using them:

-ifdef(debug)

-define(DBG(Str,Args),io:format(Str,Args))

-else

-define(DBG(Str,Args),ok)

-endif

In code you can use the following:

?DBG("~p:call(~p) called~n",[?MODULE,Request])

If you want to turn on the debugging of the system, you need to set the debugging label, you can use the command in the terminal:

c(Module,[{d,debug}])

Or you can do this programmatically using compile:file/2, you can reset the labels using c(Module,[{u,debug}]) .

5. To debug the macro definition, you can let the compiler save the result of epp processing the file to a file, you can use c(Module,['P']) in the terminal, and you can use the function compile:file in the program /2. These commands save the results to the file Module.P. The 'P' tag is different from the 'E' tag because the necessary transcoding of the record type is not done by 'P'.

Include file

1. It is customary to define records and macros into an include file, so that they can be shared across multiple modules of the entire project, not just in one module. In order to make existing definitions available in multiple modules, you can Put them in a separate file, then use the -include directive in the module, which is usually placed after the module and export directives:

-include("File.hrl")

In the preceding directive, double quotes "..." around the filename are mandatory. Included files have the suffix .hrl, but this is not mandatory.

2. The compiler has a list of paths to search for include files, where the first path is the current directory and the second is the directory containing the source code to be compiled. Additional path lists can be included at compile time using the i option: c(Module,[{i,Dir}]). Multiple directories can be specified, and the last specified directory will be searched first.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326504012&siteId=291194637