Erlang - Hướng dẫn nhanh
Erlang là một ngôn ngữ lập trình chức năng cũng có môi trường thời gian chạy. Nó được xây dựng theo cách tích hợp hỗ trợ đồng thời, phân phối và khả năng chịu lỗi. Erlang ban đầu được phát triển để sử dụng trong một số hệ thống viễn thông lớn của Ericsson.
Phiên bản đầu tiên của Erlang được phát triển bởi Joe Armstrong, Robert Virding và Mike Williams vào năm 1986. Ban đầu nó là ngôn ngữ độc quyền của Ericsson. Sau đó nó được phát hành dưới dạng ngôn ngữ mã nguồn mở vào năm 1998. Erlang, cùng với OTP, một tập hợp các phần mềm trung gian và thư viện trong Erlang, hiện được hỗ trợ và duy trì bởi đơn vị sản phẩm OTP tại Ericsson và được gọi rộng rãi làErlang/OTP.
Tại sao Erlang?
Erlang nên được sử dụng để phát triển ứng dụng của bạn, nếu bạn có các yêu cầu sau:
Ứng dụng cần xử lý một số lượng lớn các hoạt động đồng thời.
Nó phải dễ dàng phân phối qua một mạng máy tính.
Cần có một cơ sở để làm cho ứng dụng có thể chịu lỗi đối với cả lỗi phần mềm và phần cứng.
Ứng dụng phải có khả năng mở rộng. Điều này có nghĩa là nó phải có khả năng mở rộng trên nhiều máy chủ với ít hoặc không thay đổi.
Nó sẽ dễ dàng nâng cấp và cấu hình lại mà không cần phải dừng và khởi động lại ứng dụng.
Ứng dụng phải đáp ứng người dùng trong một số khung thời gian nghiêm ngặt nhất định.
Trang web chính thức của Erlang là https://www.erlang.org/.
Bây giờ trước khi có thể bắt đầu làm việc trên Erlang, bạn cần đảm bảo rằng bạn có phiên bản Erlang đầy đủ chức năng đang chạy trên hệ thống của mình. Phần này sẽ xem xét quá trình cài đặt Erlang và cấu hình tiếp theo của nó trên máy tính windows để bắt đầu với Erlang.
Đảm bảo rằng các yêu cầu hệ thống sau được đáp ứng trước khi tiến hành cài đặt.
System Requirements
Ký ức | RAM 2 GB (khuyến nghị) |
---|---|
Dung lượng đĩa | Không có yêu cầu tối thiểu. Tốt nhất là có đủ dung lượng để lưu trữ các ứng dụng sẽ được tạo bằng Erlang. |
Phiên bản hệ điều hành | Erlang có thể được cài đặt trên Windows, Ubuntu / Debian, Mac OS X. |
Đang tải xuống Erlang
Để tải xuống Erlang, người ta phải truy cập url sau - www.erlang.org/downloads .
Trang này có nhiều loại tải xuống và cũng có các bước cần thiết để tải xuống và cài đặt ngôn ngữ trên nền tảng Linux và Mac.
Nhấp vào 'Tệp nhị phân OTP 18.3 Windows 32-bit' để bắt đầu tải xuống tệp Cài đặt Windows Erlang.
Cài đặt Erlang
Các bước sau trình bày chi tiết cách cài đặt Erlang trên Windows:
Step 1- Khởi chạy Trình cài đặt đã tải xuống trong phần trước đó. Sau khi trình cài đặt khởi động, bấm Chạy.
Step 2 - Nhấn Next trên màn hình sau để chấp nhận các thành phần mặc định sẽ được cài đặt.
Step 3 - Chấp nhận đường dẫn cài đặt mặc định và nhấn Next.
Step 4 - Chấp nhận mục Start Menu mặc định sẽ được tạo và nhấn Next.
Step 5 - Sau khi cài đặt xong, bấm Close để hoàn tất cài đặt.
Cấu hình Erlang
Sau khi cài đặt xong, cần thực hiện cấu hình sau để đảm bảo rằng Erlang bắt đầu hoạt động trên hệ thống.
Hệ điều hành | Đầu ra |
---|---|
các cửa sổ | Nối chuỗi; C: \ Program Files (x86) \ erl7.2.1 \ bin HOẶC C: \ Program Files \ erl7.2.1 \ bin vào cuối biến hệ thống PATH. |
Nếu bây giờ bạn mở dấu nhắc lệnh và nhập erl, bạn sẽ có thể nhận được dấu nhắc lệnh erl.
Xin chúc mừng, bây giờ bạn đã cấu hình thành công erl trên máy tính xách tay của mình.
Cài đặt Plugin-in trên IDE phổ biến
Erlang như một ngôn ngữ lập trình cũng có sẵn trong các IDE phổ biến như Eclipse and IntelliJ. Hãy xem cách chúng ta có thể lấy các plugin cần thiết trong các IDE này để bạn có nhiều lựa chọn hơn khi làm việc với Erlang.
Cài đặt trong Eclipse
Step 1 - Mở Eclipse và nhấp vào mục Menu, Help → Install New Software.
Step 2 - Nhập Công việc với liên kết dưới dạng https://download.erlide.org/update
Sau đó nhấp vào Thêm.
Step 3 - Sau đó, bạn sẽ được nhắc nhập Tên cho plugin, hãy nhập tên là Erlide. Nhấp vào Ok.
Step 4- Sau đó Eclipse sẽ quét liên kết được cung cấp và lấy các plugin cần thiết. Kiểm tra các plugin và nhấp vào Tiếp theo.
Step 5- Trong hộp thoại tiếp theo, Eclipse sẽ hiển thị tất cả các thành phần sẽ được cài đặt. Bấm tiếp.
Step 6- Trong hộp thoại tiếp theo, Eclipse sẽ chỉ yêu cầu xem lại các thành phần đang được cài đặt. Bấm tiếp.
Step 7- Trong hộp thoại tiếp theo, bạn chỉ cần chấp nhận thỏa thuận cấp phép. Cuối cùng, nhấp vào nút Hoàn tất.
Sau đó, quá trình cài đặt sẽ bắt đầu và sau khi hoàn tất, nó sẽ nhắc bạn khởi động lại Eclipse.
Sau khi khởi động lại Eclipse, khi bạn tạo một dự án, bạn cũng có thể thấy Erlang như một tùy chọn.
Cài đặt trong IntelliJ
Vui lòng làm theo các bước tiếp theo để cài đặt IntelliJ trong máy tính của bạn.
Step 1 - Mở IntelliJ và nhấp vào Cấu hình → Phần bổ sung.
Step 2- Gõ Erlang vào hộp tìm kiếm. Bạn sẽ nhận được plugin Erlang ở phía bên tay phải của màn hình. Nhấp vào nút Cài đặt.
Step 3 - Sau khi cài đặt plugin Erlang, bạn sẽ được nhắc khởi động lại IDE.
Khi bạn khởi động lại IDE và cố gắng tạo một dự án mới, bạn sẽ thấy tùy chọn tạo dự án Erlang.
Để hiểu cú pháp cơ bản của Erlang, trước tiên chúng ta hãy xem một Hello World chương trình.
Thí dụ
% hello world program
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite("Hello, world!\n").
Những điều sau đây cần được lưu ý về chương trình trên:
Dấu% được sử dụng để thêm nhận xét vào chương trình.
Câu lệnh mô-đun giống như thêm một không gian tên như trong bất kỳ ngôn ngữ lập trình nào. Vì vậy, ở đây, chúng tôi đang đề cập rằng mã này sẽ là một phần của mô-đun có tênhelloworld.
Hàm xuất được sử dụng để có thể sử dụng bất kỳ hàm nào được định nghĩa trong chương trình. Chúng tôi đang định nghĩa một hàm được gọi là bắt đầu và để sử dụng hàm bắt đầu, chúng tôi phải sử dụng câu lệnh xuất. Các/0 có nghĩa là hàm 'start' của chúng ta chấp nhận 0 tham số.
Cuối cùng chúng tôi xác định chức năng bắt đầu của chúng tôi. Ở đây chúng tôi sử dụng một mô-đun khác được gọi làiocó tất cả các chức năng Đầu ra Đầu vào cần thiết trong Erlang. Chúng tôi đã sử dụngfwrite chức năng xuất “Hello World” ra bảng điều khiển.
Đầu ra của chương trình trên sẽ là:
Đầu ra
Hello, world!
Hình thức chung của một tuyên bố
Trong Erlang, bạn đã thấy rằng có những ký hiệu khác nhau được sử dụng trong ngôn ngữ Erlang. Hãy xem qua những gì chúng ta đã thấy từ một chương trình Hello World đơn giản -
Biểu tượng gạch nối (–)thường được sử dụng cùng với mô-đun, câu lệnh nhập và xuất. Biểu tượng gạch nối được sử dụng để cung cấp ý nghĩa cho mỗi câu lệnh tương ứng. Vì vậy, các ví dụ từ chương trình Hello world được trình bày trong chương trình sau:
-module(helloworld).
-export([start/0]).
Mỗi câu lệnh được phân tách bằng dấu chấm (.)Biểu tượng. Mỗi câu lệnh trong Erlang cần phải kết thúc bằng dấu phân cách này. Một ví dụ từ chương trình Hello world như trong chương trình sau:
io:fwrite("Hello, world!\n").
Dấu gạch chéo (/) biểu tượng được sử dụng cùng với hàm để xác định số lượng các tham số được hàm chấp nhận.
-export([start/0]).
Mô-đun
Trong Erlang, tất cả mã được chia thành các mô-đun. Một mô-đun bao gồm một chuỗi các thuộc tính và khai báo chức năng. Nó cũng giống như một khái niệm về không gian tên trong các ngôn ngữ lập trình khác được sử dụng để phân tách các đơn vị mã khác nhau một cách hợp lý.
Xác định một mô-đun
Một mô-đun được xác định với mã định danh mô-đun. Cú pháp chung và ví dụ như sau.
Cú pháp
-module(ModuleName)
Các ModuleName cần giống với tên tệp trừ phần mở rộng .erl. Nếu không việc tải mã sẽ không hoạt động như dự định.
Thí dụ
-module(helloworld)
Các Mô-đun này sẽ được đề cập chi tiết trong các chương tiếp theo, điều này chỉ để giúp bạn hiểu cơ bản về cách một mô-đun nên được định nghĩa.
Báo cáo nhập khẩu trong Erlang
Trong Erlang, nếu muốn sử dụng chức năng của mô-đun Erlang hiện có, người ta có thể sử dụng câu lệnh nhập. Dạng chung của câu lệnh nhập được mô tả trong chương trình sau:
Thí dụ
-import (modulename, [functionname/parameter]).
Ở đâu,
Modulename - Đây là tên của mô-đun cần được nhập.
functionname/parameter - Chức năng trong mô-đun cần được nhập.
Hãy thay đổi cách chúng ta viết chương trình hello world để sử dụng câu lệnh nhập. Ví dụ sẽ được hiển thị trong chương trình sau đây.
Thí dụ
% hello world program
-module(helloworld).
-import(io,[fwrite/1]).
-export([start/0]).
start() ->
fwrite("Hello, world!\n").
Trong đoạn mã trên, chúng tôi đang sử dụng từ khóa nhập để nhập thư viện 'io' và cụ thể là fwritechức năng. Vì vậy, bây giờ bất cứ khi nào chúng ta gọi hàm fwrite, chúng ta không cần phải đề cập đếnio tên mô-đun ở khắp mọi nơi.
Từ khóa trong Erlang
Từ khoá là một từ dành riêng trong Erlang không được sử dụng cho bất kỳ mục đích nào khác ngoài mục đích mà nó đã được dự định. Sau đây là danh sách các từ khóa trong Erlang.
sau | và | andalso | ban nhạc |
bắt đầu | bnot | bor | bsl |
bsr | bxor | trường hợp | nắm lấy |
chung cư | div | kết thúc | vui vẻ |
nếu | để cho | không phải | của |
hoặc là | hoặc cái gì đó khác | nhận được | rem |
thử | khi nào | xor |
Nhận xét trong Erlang
Nhận xét được sử dụng để ghi lại mã của bạn. Nhận xét dòng đơn được xác định bằng cách sử dụng%ký hiệu tại bất kỳ vị trí nào trong dòng. Sau đây là một ví dụ cho tương tự -
Thí dụ
% hello world program
-module(helloworld).
% import function used to import the io module
-import(io,[fwrite/1]).
% export function used to ensure the start function can be accessed.
-export([start/0]).
start() ->
fwrite("Hello, world!\n").
Vỏ Erlang được sử dụng để kiểm tra các biểu thức. Do đó, kiểm tra có thể được thực hiện trong shell rất dễ dàng trước khi nó thực sự được kiểm tra trong chính ứng dụng.
Ví dụ sau đây cho thấy cách biểu thức cộng có thể được sử dụng trong shell. Điều cần lưu ý ở đây là biểu thức cần kết thúc bằng dấu phân cách dấu chấm (.).
Sau khi lệnh được thực thi, trình bao sẽ in ra một dấu nhắc khác, lần này là cho Lệnh Số 2 (vì số lệnh tăng lên mỗi khi nhập lệnh mới).
Các hàm sau là hàm phổ biến nhất được sử dụng trong Erlang shell.
b() - In các ràng buộc biến hiện tại.
Syntax - b ().
For example- Sau đây là một ví dụ về cách hàm được sử dụng. Đầu tiên một biến được gọi làStr được xác định, có giá trị abcd. Sau đób() được sử dụng để hiển thị tất cả các biến liên kết.
f() - Loại bỏ tất cả các ràng buộc biến hiện tại.
Syntax - f ().
For example- Sau đây là một ví dụ về cách hàm được sử dụng. Đầu tiên, một biến được gọi là Str được định nghĩa có giá trị abcd. Sau đó, f () được sử dụng để loại bỏ ràng buộc biến Str. Sau đó, b () được gọi để đảm bảo ràng buộc đã được gỡ bỏ thành công.
f(x) - Loại bỏ ràng buộc cho một biến cụ thể.
Syntax- f (x). Trong đó, x - là biến cần loại bỏ ràng buộc.
For example- Sau đây là một ví dụ về cách hàm được sử dụng. Đầu tiên một biến được gọi là Str và Str1 được định nghĩa. Sau đó, f (Str) được sử dụng để loại bỏ ràng buộc biến Str. Sau đó, b () được gọi để đảm bảo ràng buộc đã được gỡ bỏ thành công.
h() - In danh sách lịch sử của tất cả các lệnh được thực hiện trong trình bao.
Syntax - h ().
For example - Ví dụ về lệnh h (), in lịch sử của các lệnh được thực hiện trong trình bao được hiển thị trong ảnh chụp màn hình sau.
history(N)- Đặt số lượng lệnh trước đó để giữ trong danh sách lịch sử thành N. Số lệnh trước đó được trả về. Số mặc định là 20.
Syntax- lịch sử (N). Trong đó, N - là số mà danh sách lịch sử lệnh cần được giới hạn.
For example - Ví dụ về lệnh history (N) được hiển thị trong ảnh chụp màn hình sau.
e(N)- Lặp lại lệnh N, nếu N dương. Nếu nó là số âm, lệnh thứ N trước đó được lặp lại (tức là, e (-1) lặp lại lệnh trước đó).
Syntax- e (N). Trong đó, N - là lệnh ở vị trí thứ N trong danh sách.
For example- Ví dụ về lệnh e (N) được hiển thị bên dưới. Vì chúng ta đã thực hiện lệnh e (-1), nó sẽ thực hiện lệnh trước đó là history (5).
Trong bất kỳ ngôn ngữ lập trình nào, bạn cần sử dụng một số biến để lưu trữ các loại thông tin khác nhau. Các biến không là gì ngoài các vị trí bộ nhớ dành riêng để lưu trữ các giá trị. Điều này có nghĩa là khi bạn tạo một biến, bạn dành một số không gian trong bộ nhớ để lưu giá trị được liên kết với biến đó.
Bạn có thể muốn lưu trữ thông tin của nhiều kiểu dữ liệu khác nhau như chuỗi, ký tự, ký tự rộng, số nguyên, dấu phẩy động, Boolean, v.v. Dựa trên kiểu dữ liệu của một biến, hệ điều hành phân bổ bộ nhớ và quyết định những gì có thể được lưu trữ trong ký ức.
Các loại dữ liệu tích hợp
Erlang cung cấp nhiều loại dữ liệu tích hợp sẵn. Sau đây là danh sách các kiểu dữ liệu được định nghĩa trong Erlang:
Number - Trong Erlang, có 2 loại chữ số là số nguyên và số float.
Atom- Một nguyên tử là một chữ, một hằng số có tên. Một nguyên tử phải được đặt trong dấu ngoặc đơn (') nếu nó không bắt đầu bằng chữ thường hoặc nếu nó chứa các ký tự khác ngoài ký tự chữ và số, dấu gạch dưới (_) hoặc @.
Boolean - Kiểu dữ liệu Boolean trong Erlang là hai nguyên tử dành riêng: true và false.
Bit String - Một chuỗi bit được sử dụng để lưu trữ một vùng bộ nhớ chưa được đánh máy.
Tuple- Tuple là kiểu dữ liệu ghép với số hạng cố định. Mỗi Thuật ngữ trong bộ được gọi là một phần tử. Số phần tử được cho là kích thước của bộ tuple.
Map- Bản đồ là một kiểu dữ liệu phức hợp với một số lượng các liên kết khóa-giá trị thay đổi. Mỗi liên kết khóa-giá trị trong bản đồ được gọi là một cặp liên kết. Các phần chính và giá trị của cặp được gọi là phần tử. Số lượng các cặp kết hợp được cho là kích thước của bản đồ.
List- Danh sách là kiểu dữ liệu ghép với số hạng thay đổi. Mỗi thuật ngữ trong danh sách được gọi là một phần tử. Số phần tử được cho là độ dài của danh sách.
Note- Bạn sẽ ngạc nhiên khi thấy rằng bạn không thể nhìn thấy kiểu Chuỗi ở bất kỳ đâu trong danh sách trên. Đó là bởi vì không có kiểu dữ liệu chuỗi được xác định độc quyền trong Erlang. Nhưng chúng ta sẽ xem cách chúng ta có thể làm việc với chuỗi trong chương tiếp theo.
Sau đây là các ví dụ về cách sử dụng từng kiểu dữ liệu. Một lần nữa, mỗi kiểu dữ liệu sẽ được thảo luận chi tiết trong các chương tiếp theo. Đây chỉ là để bạn làm quen với mô tả ngắn gọn về các kiểu dữ liệu được đề cập ở trên.
Con số
Ví dụ về cách sử dụng kiểu dữ liệu số được hiển thị trong chương trình sau. Chương trình này hiển thị phép cộng 2 số nguyên.
Example
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite("~w",[1+1]).
Đầu ra của chương trình trên sẽ là:
Output
2
Atom
Nguyên tử phải bắt đầu bằng một chữ cái viết thường và có thể chứa các ký tự viết thường và viết hoa, chữ số, dấu gạch dưới (_) và dấu hiệu "tại" (@). Chúng ta cũng có thể đặt một nguyên tử trong dấu ngoặc kép.
Ví dụ về cách sử dụng kiểu dữ liệu nguyên tử được trình bày trong chương trình sau. Trong chương trình này, chúng ta đang tạo ra một nguyên tử được gọi là atom1.
Example
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite(atom1).
Đầu ra của chương trình trên sẽ là:
Output
atom1
Boolean
Ví dụ về cách sử dụng kiểu dữ liệu Boolean được hiển thị trong chương trình sau. Ví dụ này thực hiện so sánh giữa 2 số nguyên và in kết quả Boolean ra bảng điều khiển.
Example
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite(2 =< 3).
Đầu ra của chương trình trên sẽ là:
Output
true
Chuỗi bit
Ví dụ về cách sử dụng kiểu dữ liệu Chuỗi Bit được trình bày trong chương trình sau. Chương trình này định nghĩa một Chuỗi bit bao gồm 2 bit. Cácbinary_to_list là một hàm có sẵn được định nghĩa trong Erlang có thể được sử dụng để chuyển đổi một Chuỗi Bit thành một danh sách.
Example
-module(helloworld).
-export([start/0]).
start() ->
Bin1 = <<10,20>>,
X = binary_to_list(Bin1),
io:fwrite("~w",[X]).
Đầu ra của chương trình trên sẽ là:
Output
[10,20]
Tuple
Ví dụ về cách sử dụng kiểu dữ liệu Tuple được trình bày trong chương trình sau.
Ở đây chúng tôi đang xác định một Tuple Ptrong đó có 3 điều khoản. Cáctuple_size là một hàm có sẵn được định nghĩa trong Erlang, có thể được sử dụng để xác định kích thước của tuple.
Example
-module(helloworld).
-export([start/0]).
start() ->
P = {john,24,{june,25}} ,
io:fwrite("~w",[tuple_size(P)]).
Đầu ra của chương trình trên sẽ là:
Output
3
Bản đồ
Ví dụ về cách sử dụng kiểu dữ liệu Bản đồ được trình bày trong chương trình sau.
Ở đây chúng tôi đang xác định một Map M1trong đó có 2 ánh xạ. Cácmap_size là một hàm có sẵn được định nghĩa trong Erlang, có thể được sử dụng để xác định kích thước của bản đồ.
Example
-module(helloworld).
-export([start/0]).
start() ->
M1 = #{name=>john,age=>25},
io:fwrite("~w",[map_size(M1)]).
Đầu ra của chương trình trên sẽ là:
Output
2
Danh sách
Ví dụ về cách sử dụng kiểu dữ liệu Danh sách được hiển thị trong chương trình sau.
Ở đây chúng tôi đang xác định một List Ltrong đó có 3 mục. Độ dài là một hàm có sẵn được định nghĩa trong Erlang, hàm này có thể được sử dụng để xác định kích thước của danh sách.
Example
-module(helloworld).
-export([start/0]).
start() ->
L = [10,20,30] ,
io:fwrite("~w",[length(L)]).
Đầu ra của chương trình trên sẽ là:
Output
3
Trong Erlang, tất cả các biến được ràng buộc với câu lệnh '='. Tất cả các biến cần bắt đầu bằng ký tự viết hoa. Trong các ngôn ngữ lập trình khác, dấu '=' được sử dụng cho phép gán, nhưng không phải trong trường hợp của Erlang. Như đã nêu, các biến được định nghĩa bằng cách sử dụng câu lệnh '='.
Một điều quan trọng cần lưu ý trong Erlang là các biến là bất biến, có nghĩa là để giá trị của biến thay đổi, nó cần phải bị hủy và tạo lại một lần nữa.
Các biến cơ bản sau trong Erlang được giải thích trong chương cuối:
Numbers- Điều này được sử dụng để biểu diễn một số nguyên hoặc một số thực. Một ví dụ là 10.
Boolean - Giá trị này đại diện cho một giá trị Boolean có thể đúng hoặc sai.
Bit String- Một chuỗi bit được sử dụng để lưu trữ một vùng bộ nhớ chưa được đánh máy. Một ví dụ là << 40,50 >>.
Tuple- Tuple là kiểu dữ liệu ghép với số hạng cố định. Một ví dụ là {40,50}.
Map- Bản đồ là một kiểu dữ liệu phức hợp với một số lượng các liên kết khóa-giá trị thay đổi. Mỗi liên kết khóa-giá trị trong bản đồ được gọi là một cặp liên kết. Ví dụ là {type => person, age => 25}.
List- Danh sách là kiểu dữ liệu ghép với số hạng thay đổi. Một ví dụ là [40,40].
Khai báo biến
Cú pháp chung của việc xác định một biến như sau:
Cú pháp
var-name = var-value
Ở đâu,
var-name - Đây là tên của biến.
var-value - Đây là giá trị liên kết với biến.
Sau đây là một ví dụ về khai báo biến:
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
X = 40,
Y = 50,
Result = X + Y,
io:fwrite("~w",[Result]).
Trong ví dụ trên, chúng ta có 2 biến, một là X được ràng buộc với giá trị 40 và tiếp theo là Y được ràng buộc với giá trị 50. Một biến khác có tên là Kết quả được ràng buộc với phép cộng X và Y.
Đầu ra của chương trình trên sẽ là:
Đầu ra
90
Đặt tên biến
Như đã thảo luận, tên biến phải bắt đầu bằng chữ hoa. Hãy lấy một ví dụ về một biến được khai báo bằng chữ thường.
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
X = 40,
Y = 50,
result = X + Y,
io:fwrite("~w",[Result]).
Nếu bạn cố gắng biên dịch chương trình trên, bạn sẽ gặp lỗi thời gian biên dịch sau.
Đầu ra
helloworld.erl:8: variable 'Result' is unbound
Thứ hai, tất cả các biến chỉ có thể được gán một lần. Hãy lấy một ví dụ về việc gán một biến nhiều lần.
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
X = 40,
Y = 50,
X = 60,
io:fwrite("~w",[X]).
Nếu bạn cố gắng biên dịch chương trình trên, bạn sẽ nhận được lỗi thời gian biên dịch sau.
Đầu ra
helloworld.erl:6: Warning: variable 'Y' is unused
helloworld.erl:7: Warning: no clause will ever match
helloworld.erl:7: Warning: the guard for this clause evaluates to 'false'
In các biến
Trong phần này chúng ta sẽ thảo luận về cách sử dụng các hàm khác nhau của biến in.
Sử dụng hàm io: fwrite
Bạn sẽ thấy điều này (io: fwrite) được sử dụng trong tất cả các chương trình trên. Cácfwrite hàm là một phần của mô-đun 'io' hoặc Erlang, có thể được sử dụng để xuất giá trị của các biến trong chương trình.
Ví dụ sau cho thấy một vài tham số khác có thể được sử dụng với câu lệnh fwrite.
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
X = 40.00,
Y = 50.00,
io:fwrite("~f~n",[X]),
io:fwrite("~e",[Y]).
Đầu ra của chương trình trên sẽ là:
Đầu ra
40.000000
5.00000e+1
Những điểm sau đây cần được lưu ý về chương trình trên.
~ - Ký tự này tượng trưng rằng một số định dạng cần được thực hiện cho đầu ra.
~f- Đối số là một float được viết là [-] ddd.ddd, trong đó độ chính xác là số chữ số sau dấu thập phân. Độ chính xác mặc định là 6 và nó không được nhỏ hơn 1.
~n - Đây là để println sang một dòng mới.
~e- Đối số là một số float được viết là [-] d.ddde + -ddd, trong đó độ chính xác là số chữ số được viết. Độ chính xác mặc định là 6 và nó không được nhỏ hơn 2.
Một toán tử là một ký hiệu yêu cầu trình biên dịch thực hiện các thao tác toán học hoặc logic cụ thể.
Erlang có các loại toán tử sau:
- Toán tử số học
- Toán tử quan hệ
- Toán tử logic
- Toán tử bitwise
Toán tử số học
Ngôn ngữ Erlang hỗ trợ các toán tử Số học bình thường như bất kỳ ngôn ngữ nào. Sau đây là các toán tử Số học có sẵn trong Erlang.
Hiển thị các ví dụ
Nhà điều hành | Sự miêu tả | Thí dụ |
---|---|---|
+ | Phép cộng hai toán hạng | 1 + 2 sẽ cho 3 |
- | Trừ toán hạng thứ hai với toán hạng đầu tiên | 1 - 2 sẽ cho -1 |
* | Phép nhân của cả hai toán hạng | 2 * 2 sẽ cho 4 |
/ | Chia tử số cho mẫu số | 2/2 sẽ cho 1 |
rem | Phần dư của số thứ nhất chia cho số thứ hai | 3 rem 2 sẽ cho 1 |
div | Thành phần div sẽ thực hiện phép chia và trả về thành phần số nguyên. | 3 div 2 sẽ cho 1 |
Toán tử quan hệ
Các toán tử quan hệ cho phép so sánh các đối tượng. Sau đây là các toán tử quan hệ có sẵn trong Erlang.
Hiển thị các ví dụ
Nhà điều hành | Sự miêu tả | Thí dụ |
---|---|---|
== | Kiểm tra sự bằng nhau giữa hai đối tượng | 2 = 2 sẽ cho đúng |
/ = | Kiểm tra sự khác biệt giữa hai đối tượng | 3 / = 2 sẽ cho đúng |
< | Kiểm tra xem đối tượng bên trái có nhỏ hơn toán hạng bên phải hay không. | 2 <3 sẽ cho đúng |
= < | Kiểm tra xem đối tượng bên trái nhỏ hơn hoặc bằng toán hạng bên phải. | 2 = <3 sẽ cho đúng |
> | Kiểm tra xem đối tượng bên trái có lớn hơn toán hạng bên phải hay không. | 3> 2 sẽ cho đúng |
> = | Kiểm tra xem đối tượng bên trái có lớn hơn hoặc bằng toán hạng bên phải hay không. | 3> = 2 sẽ cho đúng |
Toán tử logic
Các toán tử logic này được sử dụng để đánh giá các biểu thức Boolean. Sau đây là các toán tử logic có sẵn trong Erlang.
Hiển thị các ví dụ
Nhà điều hành | Sự miêu tả | Thí dụ |
---|---|---|
hoặc là | Đây là toán tử logic "hoặc" | đúng hoặc đúng sẽ cho đúng |
và | Đây là toán tử logic "và" | Đúng và sai sẽ cho sai |
không phải | Đây là toán tử logic "không phải" | không sai sẽ cho đúng |
xor | Đây là toán tử "xor" độc quyền hợp lý | True xor false sẽ cho true |
Toán tử Bitwise
Erlang cung cấp bốn toán tử bitwise. Sau đây là các toán tử bitwise có sẵn trong Erlang.
Hiển thị các ví dụ
Sr.No. | Nhà điều hành & Mô tả |
---|---|
1 | band Đây là toán tử "và" theo bitwise |
2 | bor Đây là toán tử "hoặc" theo bitwise |
3 | bxor Đây là bitwise "xor" hoặc Exclusive hoặc toán tử |
4 | bnot Đây là toán tử phủ định theo bit |
Sau đây là bảng sự thật hiển thị các toán tử này:
p | q | p & q | p | q | p ^ q |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
ưu tiên điều hành
Bảng sau đây cho thấy ưu tiên toán tử cho các toán tử Erlang theo thứ tự ưu tiên giảm dần cùng với tính kết hợp của chúng. Mức độ ưu tiên của toán tử và tính liên kết được sử dụng để xác định thứ tự đánh giá trong các biểu thức không có dấu ngoặc đơn.
Các nhà khai thác | Sự liên kết |
---|---|
: | |
# | |
bnot, không phải | |
/, *, div, rem, ban nhạc và | Liên kết trái |
+, -, bor, bxor hoặc, xor | Liên kết trái |
==, / =, = <, <,> =,> |
Erlang là một ngôn ngữ lập trình chức năng và điều cần nhớ về tất cả các ngôn ngữ lập trình chức năng là chúng không cung cấp bất kỳ cấu trúc nào cho các vòng lặp. Thay vào đó, lập trình hàm phụ thuộc vào một khái niệm gọi là đệ quy.
trong khi Thực hiện Tuyên bố
Vì không có câu lệnh while trực tiếp có sẵn trong Erlang, người ta phải sử dụng các kỹ thuật đệ quy có sẵn trong Erlang để thực hiện việc triển khai câu lệnh while.
Chúng tôi sẽ cố gắng làm theo cách triển khai tương tự của vòng lặp while như sau trong các ngôn ngữ lập trình khác. Sau đây là quy trình chung sẽ được theo sau.
Hãy xem một ví dụ về cách chúng ta có thể sử dụng đệ quy để triển khai while vòng lặp trong Erlang.
Thí dụ
-module(helloworld).
-export([while/1,while/2, start/0]).
while(L) -> while(L,0).
while([], Acc) -> Acc;
while([_|T], Acc) ->
io:fwrite("~w~n",[Acc]),
while(T,Acc+1).
start() ->
X = [1,2,3,4],
while(X).
Những điểm chính sau đây cần được lưu ý về chương trình trên:
Định nghĩa một hàm đệ quy được gọi là while sẽ mô phỏng việc thực hiện vòng lặp while của chúng ta.
Nhập danh sách các giá trị được xác định trong biến X vào hàm while của chúng tôi làm ví dụ.
Hàm while nhận từng giá trị danh sách và lưu giá trị trung gian trong biến 'Acc'.
Sau đó, vòng lặp while được gọi đệ quy cho mỗi giá trị trong danh sách.
Đầu ra của đoạn mã trên sẽ là:
Đầu ra
0
1
2
3
cho Tuyên bố
Vì không có trực tiếp for câu lệnh có sẵn trong Erlang, người ta phải sử dụng các kỹ thuật đệ quy có sẵn trong Erlang để thực hiện for thực hiện tuyên bố.
Chúng tôi sẽ cố gắng thực hiện theo cùng một cách triển khai fornhư sau trong các ngôn ngữ lập trình khác. Sau đây là quy trình chung cần được tuân thủ.
Hãy xem một ví dụ về cách chúng ta có thể sử dụng đệ quy để triển khai for vòng lặp trong Erlang.
Thí dụ
-module(helloworld).
-export([for/2,start/0]).
for(0,_) ->
[];
for(N,Term) when N > 0 ->
io:fwrite("Hello~n"),
[Term|for(N-1,Term)].
start() ->
for(5,1).
Những điểm chính sau đây cần được lưu ý về chương trình trên:
Chúng tôi đang xác định một hàm đệ quy sẽ mô phỏng việc triển khai for loop.
Chúng tôi đang sử dụng một bảo vệ trong hàm 'for' để đảm bảo rằng giá trị của N hoặc giới hạn là một giá trị dương.
Chúng ta gọi một cách đệ quy hàm for, bằng cách giảm giá trị của N tại mỗi lần đệ quy.
Đầu ra của đoạn mã trên sẽ là:
Đầu ra
Hello
Hello
Hello
Hello
Hello
Cấu trúc ra quyết định yêu cầu người lập trình phải chỉ định một hoặc nhiều điều kiện để được đánh giá hoặc kiểm tra bởi chương trình, cùng với một câu lệnh hoặc các câu lệnh sẽ được thực thi nếu điều kiện đó được xác định là truevà tùy chọn, các câu lệnh khác sẽ được thực thi nếu điều kiện được xác định là false.
Sau đây là dạng chung của cấu trúc ra quyết định điển hình được tìm thấy trong hầu hết các ngôn ngữ lập trình:
Ngôn ngữ lập trình Erlang cung cấp các loại câu lệnh ra quyết định sau.
Sr.No. | Tuyên bố & Mô tả |
---|---|
1 | Câu lệnh if An if statement bao gồm một biểu thức Boolean theo sau là một hoặc nhiều câu lệnh. |
2 | Nhiều biểu thức Các if biểu thức cũng cho phép nhiều biểu thức được đánh giá cùng một lúc. |
3 | Câu lệnh if lồng nhau Bạn có thể sử dụng một if hoặc là else if tuyên bố bên trong khác if hoặc là else if các câu lệnh). |
4 | Tuyên bố trường hợp Nó có thể được sử dụng để thực thi các biểu thức dựa trên đầu ra của câu lệnh case. |
Erlang được biết đến như một ngôn ngữ lập trình chức năng, do đó bạn sẽ thấy chú trọng nhiều vào cách các chức năng hoạt động trong Erlang. Chương này bao gồm tất cả những gì có thể được thực hiện với các chức năng trong Erlang.
Xác định một chức năng
Cú pháp của một khai báo hàm như sau:
Cú pháp
FunctionName(Pattern1… PatternN) ->
Body;
Ở đâu,
FunctionName - Tên hàm là nguyên tử.
Pattern1… PatternN- Mỗi đối số là một mẫu. Số đối số N là số hiếm của hàm. Một chức năng được xác định duy nhất bởi tên mô-đun, tên chức năng và độ hiếm. Có nghĩa là, hai chức năng có cùng tên và trong cùng một mô-đun, nhưng có tính chất khác nhau là hai chức năng khác nhau.
Body - Phần nội dung mệnh đề bao gồm một chuỗi các biểu thức được phân tách bằng dấu phẩy (,):
Chương trình sau đây là một ví dụ đơn giản về việc sử dụng các hàm:
Thí dụ
-module(helloworld).
-export([add/2,start/0]).
add(X,Y) ->
Z = X+Y,
io:fwrite("~w~n",[Z]).
start() ->
add(5,6).
Các điểm sau đây cần được lưu ý về chương trình trên:
Chúng tôi đang xác định hai chức năng, một chức năng được gọi là add trong đó có 2 tham số và tham số còn lại là start chức năng.
Cả hai chức năng đều được xác định với chức năng xuất. Nếu chúng ta không làm điều này, chúng ta sẽ không thể sử dụng chức năng.
Một hàm có thể được gọi bên trong một hàm khác. Ở đây chúng ta đang gọi hàm add từ hàm start.
Đầu ra của chương trình trên sẽ là:
Đầu ra
11
Chức năng ẩn danh
Một hàm ẩn danh là một hàm, không có tên liên quan đến nó. Erlang có cơ sở để xác định các chức năng ẩn danh. Chương trình sau đây là một ví dụ về một hàm ẩn danh.
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
Fn = fun() ->
io:fwrite("Anonymous Function") end,
Fn().
Các điểm sau đây cần lưu ý về ví dụ trên:
Chức năng ẩn danh được xác định với fun() từ khóa.
Hàm được gán cho một biến gọi là Fn.
Hàm được gọi thông qua tên biến.
Đầu ra của chương trình trên sẽ là:
Đầu ra
Anonymous Function
Các hàm với nhiều đối số
Các hàm Erlang có thể được xác định với không hoặc nhiều tham số. Quá tải hàm cũng có thể xảy ra, trong đó bạn có thể xác định một hàm có cùng tên nhiều lần, miễn là chúng có số lượng tham số khác nhau.
Trong ví dụ sau, bản trình diễn hàm được định nghĩa với nhiều đối số cho mỗi định nghĩa hàm.
Thí dụ
-module(helloworld).
-export([add/2,add/3,start/0]).
add(X,Y) ->
Z = X+Y,
io:fwrite("~w~n",[Z]).
add(X,Y,Z) ->
A = X+Y+Z,
io:fwrite("~w~n",[A]).
start() ->
add(5,6),
add(5,6,6).
Trong chương trình trên, chúng ta đang định nghĩa hàm add hai lần. Nhưng định nghĩa của hàm thêm đầu tiên có hai tham số và hàm thứ hai có ba tham số.
Đầu ra của chương trình trên sẽ là:
Đầu ra
11
17
Chức năng với Trình tự bảo vệ
Các chức năng trong Erlang cũng có khả năng có các chuỗi bảo vệ. Đây không phải là gì ngoài các biểu thức mà chỉ khi được đánh giá là true thì hàm mới chạy.
Cú pháp của một hàm với một chuỗi bảo vệ được hiển thị trong chương trình sau.
Cú pháp
FunctionName(Pattern1… PatternN) [when GuardSeq1]->
Body;
Ở đâu,
FunctionName - Tên hàm là nguyên tử.
Pattern1… PatternN- Mỗi đối số là một mẫu. Số đối số N là số hiếm của hàm. Một chức năng được xác định duy nhất bởi tên mô-đun, tên chức năng và độ hiếm. Có nghĩa là, hai chức năng có cùng tên và trong cùng một mô-đun, nhưng có tính chất khác nhau là hai chức năng khác nhau.
Body - Phần nội dung mệnh đề bao gồm một chuỗi các biểu thức được phân tách bằng dấu phẩy (,).
GuardSeq1 - Đây là biểu thức được đánh giá khi hàm được gọi.
Chương trình sau đây là một ví dụ đơn giản về việc sử dụng một hàm với một chuỗi bảo vệ.
Thí dụ
-module(helloworld).
-export([add/1,start/0]).
add(X) when X>3 ->
io:fwrite("~w~n",[X]).
start() ->
add(4).
Đầu ra của chương trình trên là:
Đầu ra
4
Nếu hàm add được gọi là add(3), chương trình sẽ báo lỗi.
Mô-đun là một loạt các chức năng được tập hợp lại trong một tệp duy nhất, dưới một tên duy nhất. Ngoài ra, tất cả các chức năng trong Erlang phải được định nghĩa trong các mô-đun.
Hầu hết các chức năng cơ bản như toán tử số học, logic và Boolean đã có sẵn vì các mô-đun mặc định được tải khi chương trình được chạy. Mọi hàm khác được xác định trong một mô-đun mà bạn sẽ sử dụng cần được gọi với biểu mẫuModule:Function (Tranh luận).
Xác định Mô-đun
Với một mô-đun, bạn có thể khai báo hai loại thứ: chức năng và thuộc tính. Thuộc tính là siêu dữ liệu mô tả chính mô-đun như tên của nó, các chức năng cần hiển thị với thế giới bên ngoài, tác giả của mã, v.v. Loại siêu dữ liệu này rất hữu ích vì nó cung cấp gợi ý cho trình biên dịch về cách nó sẽ thực hiện công việc của mình và cũng vì nó cho phép mọi người truy xuất thông tin hữu ích từ mã đã biên dịch mà không cần phải tham khảo nguồn.
Cú pháp của một khai báo hàm như sau:
Cú pháp
-module(modulename)
Ở đâu, modulenamelà tên của mô-đun. Đây phải là dòng đầu tiên của mã trong mô-đun.
Chương trình sau đây cho thấy một ví dụ về mô-đun được gọi là helloworld.
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite("Hello World").
Đầu ra của chương trình trên là:
Đầu ra
Hello World
Thuộc tính mô-đun
Thuộc tính mô-đun xác định một thuộc tính nhất định của mô-đun. Thuộc tính mô-đun bao gồm một thẻ và một giá trị.
Cú pháp chung của một thuộc tính là -
Cú pháp
-Tag(Value)
Một ví dụ về cách thuộc tính có thể được sử dụng được hiển thị trong chương trình sau:
Thí dụ
-module(helloworld).
-author("TutorialPoint").
-version("1.0").
-export([start/0]).
start() ->
io:fwrite("Hello World").
Chương trình trên định nghĩa 2 thuộc tính tùy chỉnh được gọi là tác giả và phiên bản, chứa tác giả chương trình và số phiên bản chương trình tương ứng.
Đầu ra của chương trình trên là:
Đầu ra
Hello World
Các thuộc tính được tạo sẵn
Erlang có một số thuộc tính được tạo sẵn có thể được gắn vào các mô-đun. Chúng ta hãy nhìn vào chúng.
Xuất khẩu
Thuộc tính xuất khẩu sẽ lấy một danh sách các chức năng và độ hiếm để xuất khẩu cho các mô-đun khác. Nó sẽ xác định giao diện mô-đun. Chúng tôi đã thấy điều này trong tất cả các ví dụ trước đây của chúng tôi.
Cú pháp
export([FunctionName1/FunctionArity1,.,FunctionNameN/FunctionArityN])
Ở đâu,
FunctionName - Đây là tên của hàm trong chương trình.
FunctionArity - Đây là số tham số liên quan đến hàm.
Thí dụ
-module(helloworld).
-author("TutorialPoint").
-version("1.0").
-export([start/0]).
start() ->
io:fwrite("Hello World").
Đầu ra của chương trình trên sẽ là:
Đầu ra
Hello World
Nhập khẩu
Thuộc tính nhập được sử dụng để nhập các chức năng từ một mô-đun khác để sử dụng nó làm cục bộ.
Cú pháp
-import (modulename , [functionname/parameter]).
Ở đâu,
Modulename - Đây là tên của mô-đun cần được nhập.
functionname/parameter - chức năng trong mô-đun cần được nhập.
Thí dụ
-module(helloworld).
-import(io,[fwrite/1]).
-export([start/0]).
start() ->
fwrite("Hello, world!\n").
Trong đoạn mã trên, chúng tôi đang sử dụng từ khóa nhập để nhập thư viện 'io' và cụ thể là hàm fwrite. Vì vậy, bây giờ bất cứ khi nào chúng ta gọi hàm fwrite, chúng ta không cần phải đề cập đến tên mô-đun io ở khắp mọi nơi.
Đầu ra của chương trình trên sẽ là:
Đầu ra
Hello, world!
Đệ quy là một phần quan trọng của Erlang. Đầu tiên, hãy xem cách chúng ta có thể thực hiện đệ quy đơn giản bằng cách thực hiện chương trình giai thừa.
Thí dụ
-module(helloworld).
-export([fac/1,start/0]).
fac(N) when N == 0 -> 1;
fac(N) when N > 0 -> N*fac(N-1).
start() ->
X = fac(4),
io:fwrite("~w",[X]).
Những điều sau đây cần được lưu ý về chương trình trên:
Đầu tiên chúng ta định nghĩa một hàm gọi là fac (N).
Chúng ta có thể định nghĩa hàm đệ quy bằng cách gọi đệ quy fac (N).
Đầu ra của chương trình trên là:
Đầu ra
24
Phương pháp tiếp cận thực tế đối với đệ quy
Trong phần này, chúng ta sẽ hiểu chi tiết về các loại đệ quy khác nhau và cách sử dụng nó trong Erlang.
Đệ quy độ dài
Có thể thấy một cách tiếp cận thực tế hơn đối với đệ quy với một ví dụ đơn giản được sử dụng để xác định độ dài của một danh sách. Một danh sách có thể có nhiều giá trị như [1,2,3,4]. Hãy sử dụng đệ quy để xem làm thế nào chúng ta có thể nhận được độ dài của một danh sách.
Example
-module(helloworld).
-export([len/1,start/0]).
len([]) -> 0;
len([_|T]) -> 1 + len(T).
start() ->
X = [1,2,3,4],
Y = len(X),
io:fwrite("~w",[Y]).
Những điều sau đây cần được lưu ý về chương trình trên:
Chức năng đầu tiên len([]) được sử dụng cho điều kiện trường hợp đặc biệt nếu danh sách trống.
Các [H|T] mẫu để khớp với danh sách một hoặc nhiều phần tử, vì danh sách có độ dài một phần tử sẽ được xác định là [X|[]] và danh sách độ dài hai sẽ được xác định là [X|[Y|[]]]. Lưu ý rằng phần tử thứ hai là một danh sách. Điều này có nghĩa là chúng ta chỉ cần đếm phần tử đầu tiên và hàm có thể tự gọi phần tử thứ hai. Cho mỗi giá trị trong danh sách được tính là độ dài 1.
Đầu ra của chương trình trên sẽ là:
Output
4
Đệ quy đuôi
Để hiểu cách hoạt động của đệ quy đuôi, chúng ta hãy hiểu cách hoạt động của đoạn mã sau trong phần trước.
Syntax
len([]) -> 0;
len([_|T]) -> 1 + len(T).
Câu trả lời cho 1 + len (Nghỉ ngơi) cần câu trả lời của len (Phần còn lại) được tìm thấy. Khi đó, bản thân hàm len (Rest) cần kết quả của một lệnh gọi hàm khác được tìm thấy. Các phần bổ sung sẽ được xếp chồng lên nhau cho đến khi tìm thấy cái cuối cùng và chỉ khi đó kết quả cuối cùng mới được tính toán.
Đệ quy đuôi nhằm mục đích loại bỏ sự xếp chồng của hoạt động này bằng cách giảm chúng khi chúng xảy ra.
Để đạt được điều này, chúng ta sẽ cần phải giữ thêm một biến tạm thời làm tham số trong hàm của chúng ta. Biến tạm thời nói trên đôi khi được gọi là bộ tích lũy và hoạt động như một nơi để lưu trữ các kết quả tính toán của chúng tôi khi chúng xảy ra nhằm hạn chế sự gia tăng các lệnh gọi của chúng tôi.
Hãy xem một ví dụ về đệ quy đuôi -
Example
-module(helloworld).
-export([tail_len/1,tail_len/2,start/0]).
tail_len(L) -> tail_len(L,0).
tail_len([], Acc) -> Acc;
tail_len([_|T], Acc) -> tail_len(T,Acc+1).
start() ->
X = [1,2,3,4],
Y = tail_len(X),
io:fwrite("~w",[Y]).
Đầu ra của chương trình trên là:
Output
4
Bản sao
Hãy xem một ví dụ về đệ quy. Lần này, hãy viết một hàm nhận một số nguyên làm tham số đầu tiên và sau đó là bất kỳ số hạng nào khác làm tham số thứ hai. Sau đó, nó sẽ tạo một danh sách bao nhiêu bản sao của thuật ngữ được chỉ định bởi số nguyên.
Hãy xem ví dụ về điều này sẽ như thế nào -
-module(helloworld).
-export([duplicate/2,start/0]).
duplicate(0,_) ->
[];
duplicate(N,Term) when N > 0 ->
io:fwrite("~w,~n",[Term]),
[Term|duplicate(N-1,Term)].
start() ->
duplicate(5,1).
Đầu ra của chương trình trên sẽ là:
Đầu ra
1,
1,
1,
1,
1,
Đảo ngược danh sách
Không có giới hạn nào mà bạn có thể sử dụng đệ quy trong Erlang. Bây giờ chúng ta hãy nhanh chóng xem xét cách chúng ta có thể đảo ngược các phần tử của một danh sách bằng cách sử dụng đệ quy. Chương trình sau đây có thể được sử dụng để thực hiện điều này.
Thí dụ
-module(helloworld).
-export([tail_reverse/2,start/0]).
tail_reverse(L) -> tail_reverse(L,[]).
tail_reverse([],Acc) -> Acc;
tail_reverse([H|T],Acc) -> tail_reverse(T, [H|Acc]).
start() ->
X = [1,2,3,4],
Y = tail_reverse(X),
io:fwrite("~w",[Y]).
Đầu ra của chương trình trên sẽ là:
Đầu ra
[4,3,2,1]
Những điều sau đây cần được lưu ý về chương trình trên:
Chúng ta lại đang sử dụng khái niệm biến tạm thời để lưu trữ từng phần tử của Danh sách trong một biến có tên là Acc.
Sau đó chúng tôi gọi tail_reverse đệ quy, nhưng lần này, chúng tôi đảm bảo rằng phần tử cuối cùng được đưa vào danh sách mới trước.
Sau đó, chúng tôi gọi đệ quy tail_reverse cho từng phần tử trong danh sách.
Trong Erlang có 2 loại chữ số là số nguyên và số float. Sau đây là một số ví dụ cho thấy cách số nguyên và số thực có thể được sử dụng trong Erlang.
Integer- Ví dụ về cách sử dụng kiểu dữ liệu số dưới dạng số nguyên được trình bày trong chương trình sau. Chương trình này hiển thị phép cộng 2 số nguyên.
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite("~w",[1+1]).
Kết quả của chương trình trên sẽ như sau:
Đầu ra
2
Float- Một ví dụ về cách kiểu dữ liệu số có thể được sử dụng như một số thực được trình bày trong chương trình sau. Chương trình này hiển thị phép cộng 2 số nguyên.
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite("~w",[1.1+1.2]).
Kết quả của chương trình trên sẽ như sau:
Đầu ra
2.3
Hiển thị số nổi và số mũ
Khi sử dụng fwriteđể xuất giá trị ra bảng điều khiển, có sẵn các tham số định dạng có thể được sử dụng để xuất số dưới dạng số thực hoặc số mũ. Hãy xem làm thế nào chúng ta có thể đạt được điều này.
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite("~f~n",[1.1+1.2]),
io:fwrite("~e~n",[1.1+1.2]).
Kết quả của chương trình trên sẽ như sau:
Đầu ra
2.300000
2.30000e+0
Những điều chính sau đây cần được lưu ý về chương trình trên:
Khi tùy chọn ~ f được chỉ định, điều đó có nghĩa là đối số là một float được viết dưới dạng [-]ddd.ddd, trong đó độ chính xác là số chữ số sau dấu thập phân. Độ chính xác mặc định là 6.
Khi tùy chọn ~ e được chỉ định, điều đó có nghĩa là đối số là một float được viết dưới dạng [-]d.ddde+-ddd, trong đó độ chính xác là số chữ số được viết. Độ chính xác mặc định là 6.
Các hàm toán học cho các số
Các hàm toán học sau đây có sẵn trong Erlang cho các số. Lưu ý rằng tất cả các hàm toán học cho Erlang đều có trong thư viện toán học. Vì vậy, tất cả các ví dụ dưới đây sẽ sử dụng câu lệnh nhập để nhập tất cả các phương thức trong thư viện toán học.
Sr.No. | Chức năng Toán học & Mô tả |
---|---|
1 | tội Phương thức này trả về sin của giá trị được chỉ định. |
2 | cos Phương thức này trả về cosine của giá trị được chỉ định. |
3 | rám nắng Phương thức này trả về tiếp tuyến của giá trị được chỉ định. |
4 | asin Phương thức trả về giá trị arcsine được chỉ định. |
5 | acos Phương thức trả về arccosine của giá trị được chỉ định. |
6 | atan Phương thức trả về arctangent của giá trị được chỉ định. |
7 | exp Phương thức trả về cấp số nhân của giá trị được chỉ định. |
số 8 | khúc gỗ Phương thức trả về lôgarit của giá trị được chỉ định. |
9 | cơ bụng Phương thức trả về giá trị tuyệt đối của số được chỉ định. |
10 | Phao nổi Phương thức chuyển đổi một số thành một giá trị thực. |
11 | Is_float Phương thức kiểm tra xem một số có phải là giá trị thực hay không. |
12 | Is_Integer Phương thức kiểm tra xem một số có phải là giá trị Số nguyên hay không. |
Một chuỗi ký tự được xây dựng trong Erlang bằng cách đặt văn bản chuỗi trong dấu ngoặc kép. Các chuỗi trong Erlang cần được xây dựng bằng cách sử dụng dấu ngoặc kép, chẳng hạn như “Hello World”.
Sau đây là một ví dụ về cách sử dụng chuỗi trong Erlang:
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
Str1 = "This is a string",
io:fwrite("~p~n",[Str1]).
Ví dụ trên tạo một biến chuỗi được gọi là Str1. Chuỗi “Đây là một chuỗi” được gán cho biến và hiển thị tương ứng.
Đầu ra của chương trình trên sẽ là:
Đầu ra
“This is a string”
Tiếp theo, chúng ta sẽ thảo luận về các operations available for Strings. Lưu ý rằng đối với các hoạt động chuỗi, bạn cũng cần phải bao gồm cả thư viện chuỗi.
Sr.No | Phương thức & mô tả chuỗi |
---|---|
1 | len Phương thức trả về độ dài của một chuỗi cụ thể. |
2 | công bằng Phương thức trả về giá trị Boolean về việc một chuỗi có bằng với chuỗi khác hay không. |
3 | kết hợp Phương thức nối 2 chuỗi và trả về chuỗi đã nối. |
4 | chr Phương thức trả về vị trí chỉ mục của một ký tự trong một chuỗi. |
5 | str Phương thức trả về vị trí chỉ mục của một chuỗi con trong một chuỗi. |
6 | substr Phương thức trả về chuỗi con từ chuỗi gốc dựa trên vị trí bắt đầu và số ký tự từ vị trí bắt đầu. |
7 | trái Phương thức trả về chuỗi con từ chuỗi gốc dựa trên vị trí bắt đầu và số ký tự từ vị trí bắt đầu. |
trái với ký tự ở cuối
Phương thức trả về chuỗi con từ bên trái của chuỗi dựa trên số ký tự. Nhưng với tùy chọn bao gồm một ký tự theo sau nếu số lớn hơn độ dài của chuỗi.
Cú pháp
left(str1,number,$character)
Thông số
str1 - Đây là chuỗi mà từ đó chuỗi con cần được trích xuất.
Number - Đây là số ký tự cần có trong chuỗi con.
$Character - Ký tự để bao gồm làm ký tự theo sau.
Giá trị trả lại
Trả về chuỗi con từ chuỗi ban đầu dựa trên phía bên trái của chuỗi và số.
Ví dụ
-module(helloworld).
-import(string,[left/3]).
-export([start/0]).
start() ->
Str1 = "hello",
Str2 = left(Str1,10,$.),
io:fwrite("~p~n",[Str2]).
Đầu ra
Khi chạy chương trình trên, chúng ta sẽ nhận được kết quả như sau.
"hello....."
đúng
Phương thức trả về chuỗi con từ bên phải của chuỗi dựa trên số ký tự.
Cú pháp
right(str1,number)
Thông số
str1 - Đây là chuỗi mà từ đó chuỗi con cần được trích xuất.
Number - Đây là số ký tự cần có trong chuỗi con.
Giá trị trả lại
Trả về chuỗi con từ chuỗi ban đầu dựa trên phía bên phải của chuỗi và số.
Ví dụ
-module(helloworld).
-import(string,[right/2]).
-export([start/0]).
start() ->
Str1 = "hello World",
Str2 = right(Str1,2),
io:fwrite("~p~n",[Str2]).
Đầu ra
Khi chạy chương trình trên, chúng ta sẽ nhận được kết quả như sau.
“ld”
đúng với ký tự theo sau
Phương thức trả về chuỗi con từ bên phải của chuỗi dựa trên số ký tự. Nhưng với tùy chọn bao gồm một ký tự theo sau nếu số lớn hơn độ dài của chuỗi.
Cú pháp
right(str1,number,$character)
Thông số
str1 - Đây là chuỗi mà từ đó chuỗi con cần được trích xuất.
Number - Đây là số ký tự cần có trong chuỗi con.
$Character - Ký tự để bao gồm làm ký tự theo sau.
Giá trị trả lại
Trả về chuỗi con từ chuỗi ban đầu dựa trên phía bên phải của chuỗi và số.
Ví dụ
-module(helloworld).
-import(string,[right/3]).
-export([start/0]).
start() ->
Str1 = "hello",
Str2 = right(Str1,10,$.),
io:fwrite("~p~n",[Str2]).
Đầu ra
Khi chạy chương trình trên, chúng ta sẽ nhận được kết quả như sau.
".....hello"
to_lower
Phương thức trả về chuỗi bằng chữ thường.
Cú pháp
to_lower(str1)
Thông số
str1 - Đây là chuỗi cần được chuyển đổi thành chữ thường.
Giá trị trả lại
Trả về chuỗi ở dạng chữ thường.
Ví dụ
-module(helloworld).
-import(string,[to_lower/1]).
-export([start/0]).
start() ->
Str1 = "HELLO WORLD",
Str2 = to_lower(Str1),
io:fwrite("~p~n",[Str2]).
Đầu ra
Khi chạy chương trình trên, chúng ta sẽ nhận được kết quả như sau.
"hello world"
to_upper
Phương thức trả về chuỗi bằng chữ hoa.
Cú pháp
to_upper(str1)
Thông số
str1 - Đây là chuỗi cần được chuyển đổi sang chữ hoa.
Return Value - Trả về chuỗi ở dạng chữ hoa.
Ví dụ
-module(helloworld).
-import(string,[to_upper/1]).
-export([start/0]).
start() ->
Str1 = "hello world",
Str2 = to_upper(Str1),
io:fwrite("~p~n",[Str2]).
Đầu ra
Khi chạy chương trình trên, chúng ta sẽ nhận được kết quả như sau.
"HELLO WORLD"
chuỗi con
Trả về một chuỗi con của Chuỗi, bắt đầu từ vị trí Bắt đầu đến cuối chuỗi hoặc đến và bao gồm cả vị trí Dừng.
Cú pháp
sub_string(str1,start,stop)
Thông số
str1 - Đây là chuỗi mà từ đó chuỗi con cần được trả về.
start - Đây là vị trí bắt đầu của chuỗi con
stop - Đây là vị trí dừng của chuỗi con
Giá trị trả lại
Trả về một chuỗi con của Chuỗi, bắt đầu từ vị trí Bắt đầu đến cuối chuỗi hoặc đến và bao gồm cả vị trí Dừng.
Ví dụ
-module(helloworld).
-import(string,[sub_string/3]).
-export([start/0]).
start() ->
Str1 = "hello world",
Str2 = sub_string(Str1,1,5),
io:fwrite("~p~n",[Str2]).
Đầu ra
Khi chạy chương trình trên, chúng ta sẽ nhận được kết quả như sau.
"hello"
Danh sách là một cấu trúc được sử dụng để lưu trữ một tập hợp các mục dữ liệu. Trong Erlang, Danh sách được tạo bằng cách đặt các giá trị trong dấu ngoặc vuông.
Sau đây là một ví dụ đơn giản về việc tạo danh sách các số trong Erlang.
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
Lst1 = [1,2,3],
io:fwrite("~w~n",[Lst1]).
Kết quả của ví dụ trên sẽ là:
Đầu ra
[1 2 3]
Bây giờ chúng ta hãy thảo luận về various methods available for Lists. Lưu ý rằng thư viện danh sách cần được nhập để các phương thức này hoạt động.
Sr.No | Phương pháp và Mô tả |
---|---|
1 | tất cả Trả về true nếu Pred (Elem) trả về true cho tất cả các phần tử Elem trong List, ngược lại là false. |
2 | bất kì Trả về true nếu Pred (Elem) trả về true cho ít nhất một phần tử Elem trong Danh sách. |
3 | nối thêm Trả về một danh sách mới List3 được tạo từ các phần tử của List1 theo sau là các phần tử của List2. |
4 | xóa bỏ Xóa một phần tử khỏi danh sách và trả về một danh sách mới. |
5 | droplast Bỏ phần tử cuối cùng của một Danh sách. |
6 | bản sao Trả về danh sách chứa N bản sao của thuật ngữ Elem |
7 | Cuối cùng Trả về phần tử cuối cùng của danh sách |
số 8 | tối đa Trả về phần tử của danh sách có giá trị lớn nhất. |
9 | thành viên Kiểm tra xem một phần tử có trong danh sách hay không. |
10 | min Trả về phần tử của danh sách có giá trị nhỏ nhất. |
11 | hợp nhất Trả về danh sách đã sắp xếp được hình thành bằng cách hợp nhất tất cả các danh sách con của ListOfLists. |
12 | thứ n Trả về phần tử thứ N của Danh sách. |
13 | nthtail Trả về đuôi thứ N của Danh sách. |
14 | đảo ngược Đảo ngược danh sách các phần tử. |
15 | sắp xếp Sắp xếp danh sách các phần tử. |
16 | danh sách phụ Trả về danh sách phụ các phần tử. |
17 | Tổng Trả về tổng các phần tử trong danh sách. |
Erlang cung cấp một số phương pháp khi làm việc với I / O. Nó có các lớp dễ dàng hơn để cung cấp các chức năng sau cho tệp:
- Đọc tệp
- Ghi vào tệp
- Xem tệp là tệp hay thư mục
Phương thức hoạt động tệp trong Erlang
Hãy cùng khám phá một số thao tác với tệp mà Erlang cung cấp. Với mục đích của những ví dụ này, chúng tôi sẽ giả định rằng có một tệp được gọi làNewFile.txt trong đó có những dòng văn bản sau
Example1
Example2
Example3
Tệp này sẽ được sử dụng cho các thao tác đọc và ghi trong các ví dụ sau.
Đọc nội dung của tệp một dòng tại một thời điểm
Các thao tác chung trên tệp được thực hiện bằng cách sử dụng các phương pháp có sẵn trong thư viện tệp. Để đọc tệp, trước tiên chúng ta cần sử dụng thao tác mở và sau đó sử dụng thao tác đọc có sẵn như một phần của thư viện tệp. Sau đây là cú pháp cho cả hai phương thức này.
Cú pháp
- Mở tệp - Mở (Tệp, Chế độ)
- Đọc tệp - đọc (FileHandler, NumberofBytes)
Thông số
File - Đây là vị trí của tệp cần được mở.
Mode - Đây là chế độ mà tập tin cần được mở.
Sau đây là một số chế độ khả dụng -
Read - Tệp, phải tồn tại, được mở để đọc.
Write- Tập tin được mở để ghi. Nó được tạo ra nếu nó không tồn tại. Nếu tệp tồn tại và nếu ghi không được kết hợp với đọc, tệp sẽ bị cắt bớt.
Append- Tập tin sẽ được mở để ghi và nó sẽ được tạo nếu nó không tồn tại. Mọi thao tác ghi vào tệp được mở bằng append sẽ diễn ra ở cuối tệp.
Exclusive- Tập tin, khi được mở để ghi, được tạo nếu nó không tồn tại. Nếu tệp tồn tại, mở sẽ trả về {error, tồn tại}.
FileHandler- Đây là phần xử lý của một tệp. Tay cầm này là cái sẽ được trả lại khifile:open hoạt động được sử dụng.
NumberofByte - Đây là số byte thông tin cần được đọc từ tệp.
Giá trị trả lại
Open(File,Mode) - Trả về một xử lý cho tệp, nếu thao tác thành công.
read(FileHandler,NumberofBytes) - Trả về thông tin đã đọc được yêu cầu từ tệp.
Ví dụ
-module(helloworld).
-export([start/0]).
start() ->
{ok, File} = file:open("Newfile.txt",[read]),
Txt = file:read(File,1024 * 1024),
io:fwrite("~p~n",[Txt]).
Output - Khi chạy đoạn chương trình trên ta sẽ được kết quả như sau.
Example1
Bây giờ chúng ta hãy thảo luận một số phương pháp khác có sẵn cho các hoạt động tệp -
Sr.No. | Phương pháp & Mô tả |
---|---|
1 | file_read Có sẵn để cho phép đọc tất cả nội dung của tệp cùng một lúc. |
2 | viết Được sử dụng để ghi nội dung vào một tệp. |
3 | sao chép được sử dụng để tạo bản sao của một tệp hiện có. |
4 | xóa bỏ Phương pháp này được sử dụng để xóa một tệp hiện có. |
5 | list_dir Phương pháp này được sử dụng để liệt kê nội dung của một thư mục cụ thể. |
6 | make_dir Phương pháp này được sử dụng để tạo một thư mục mới. |
7 | đổi tên Phương pháp này được sử dụng để đổi tên một tệp hiện có. |
số 8 | Kích thước tập tin Phương pháp này được sử dụng để xác định kích thước của tệp. |
9 | is_file Phương pháp này được sử dụng để xác định xem một tệp có thực sự là một tệp hay không. |
10 | is_dir Phương pháp này được sử dụng để xác định xem một thư mục có thực sự là một thư mục hay không. |
Một nguyên tử là một nghĩa đen, một hằng số có tên. Một nguyên tử phải được đặt trong dấu ngoặc đơn (') nếu nó không bắt đầu bằng chữ thường hoặc nếu nó chứa các ký tự khác ngoài ký tự chữ và số, dấu gạch dưới (_) hoặc @.
Chương trình sau đây là một ví dụ về cách các nguyên tử có thể được sử dụng trong Erlang. Chương trình này khai báo 3 nguyên tử lần lượt là atom1, atom_1 và 'atom 1'. Vì vậy, bạn có thể thấy các cách khác nhau mà một nguyên tử có thể được khai báo.
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite(atom1),
io:fwrite("~n"),
io:fwrite(atom_1),
io:fwrite("~n"),
io:fwrite('atom 1'),
io:fwrite("~n").
Kết quả của chương trình trên sẽ như sau:
Đầu ra
atom1
atom_1
atom 1
Hãy xem một số phương pháp có sẵn trong Erlang để làm việc với các nguyên tử.
Sr.No. | Phương pháp và Mô tả |
---|---|
1 | is_atom Phương pháp này được sử dụng để xác định xem một thuật ngữ có thực sự là một nguyên tử hay không. |
2 | atom_to_list Phương pháp này được sử dụng để chuyển đổi một nguyên tử thành một danh sách. |
3 | list_to_atom Phương pháp này được sử dụng để chuyển đổi một mục danh sách thành một nguyên tử. |
4 | atom_to_binary Phương pháp này được sử dụng để chuyển đổi một nguyên tử thành một giá trị nhị phân. |
5 | binary_to_atom Phương pháp này được sử dụng để chuyển đổi một giá trị nhị phân thành một giá trị nguyên tử. |
Bản đồ là một kiểu dữ liệu kết hợp với một số lượng biến các liên kết khóa-giá trị. Mỗi liên kết khóa-giá trị trong bản đồ được gọi là một cặp liên kết. Các phần chính và giá trị của cặp được gọi là phần tử. Số lượng các cặp kết hợp được cho là kích thước của bản đồ.
Ví dụ về cách sử dụng kiểu dữ liệu Bản đồ được trình bày trong chương trình sau.
Ở đây chúng tôi đang xác định một Bản đồ M1 có 2 ánh xạ. Cácmap_size là một hàm có sẵn được định nghĩa trong Erlang có thể được sử dụng để xác định kích thước của bản đồ.
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
M1 = #{name=>john,age=>25},
io:fwrite("~w",[map_size(M1)]).
Kết quả của chương trình trên sẽ như sau.
Đầu ra
2
Một số phương pháp khác có sẵn cho bản đồ như sau.
Sr.No. | Phương pháp & Mô tả |
---|---|
1 | from_list Phương pháp này được sử dụng để tạo bản đồ từ một danh sách. |
2 | tìm thấy Phương pháp này được sử dụng để tìm xem một khóa cụ thể có tồn tại trong bản đồ hay không. |
3 | được Phương thức này được sử dụng để lấy giá trị của một khóa cụ thể trong bản đồ. |
4 | là chìa khóa Phương pháp này được sử dụng để xác định xem một khóa cụ thể có được xác định là khóa trong bản đồ hay không. |
5 | chìa khóa Phương thức này được sử dụng để trả về tất cả các khóa từ bản đồ. |
6 | hợp nhất Phương pháp này được sử dụng để hợp nhất 2 bản đồ. |
7 | đặt Phương pháp này được sử dụng để thêm một cặp giá trị khóa vào bản đồ. |
số 8 | giá trị Phương thức này được sử dụng để trả về tất cả các giá trị từ một bản đồ. |
9 | tẩy Phương pháp này được sử dụng để xóa một giá trị khóa khỏi bản đồ. |
Tuple là một kiểu dữ liệu kết hợp với một số thuật ngữ cố định. Mỗi thuật ngữ trong Tuple được gọi là một phần tử. Số lượng phần tử được cho là kích thước của Tuple.
Ví dụ về cách sử dụng kiểu dữ liệu Tuple được trình bày trong chương trình sau.
Ở đây chúng tôi đang xác định một Tuple Ptrong đó có 3 điều khoản. Cáctuple_size là một hàm có sẵn được định nghĩa trong Erlang có thể được sử dụng để xác định kích thước của Tuple.
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
P = {john,24,{june,25}} ,
io:fwrite("~w",[tuple_size(P)]).
Kết quả của chương trình trên sẽ như sau.
Đầu ra
3
Hãy xem xét thêm một số hoạt động có sẵn cho các bộ giá trị.
Sr.No. | Phương pháp & Mô tả |
---|---|
1 | is_tuple Phương pháp này được sử dụng để xác định thuật ngữ được cung cấp có thực sự là một bộ giá trị hay không. |
2 | list_to_tuple Phương pháp này là để chuyển đổi một danh sách thành một tuple. |
3 | tuple_to_list Phương pháp này là chuyển đổi một tuple thành một danh sách. |
Erlang có thêm cơ sở để tạo hồ sơ. Các bản ghi này bao gồm các trường. Ví dụ: bạn có thể xác định một bản ghi cá nhân có 2 trường, một là id và một là trường tên. Trong Erlang, sau đó bạn có thể tạo các phiên bản khác nhau của bản ghi này để xác định nhiều người với nhiều tên và id khác nhau.
Hãy khám phá cách chúng ta có thể làm việc với các bản ghi.
Tạo bản ghi
Một bản ghi được tạo bằng Mã định danh Bản ghi. Trong mã định danh bản ghi này, bạn chỉ định các trường khác nhau tạo thành bản ghi. Cú pháp chung và ví dụ được đưa ra bên dưới.
Cú pháp
record(recordname , {Field1,Field2 ..Fieldn})
Thông số
recordname - Đây là tên được đặt cho bản ghi.
Field1,Field2 ..Fieldn - Đây là danh sách các trường khác nhau tạo thành bản ghi.
Giá trị trả lại
không ai
Ví dụ
-module(helloworld).
-export([start/0]).
-record(person, {name = "", id}).
start() ->
P = #person{name="John",id = 1}.
Ví dụ trên cho thấy định nghĩa của một bản ghi có 2 trường, một là id và một là tên. Ngoài ra, một bản ghi được xây dựng theo cách sau:
Cú pháp
#recordname {fieldName1 = value1, fieldName2 = value2 .. fieldNameN = valueN}
Nơi bạn chỉ định giá trị cho các trường tương ứng khi một thể hiện của bản ghi được xác định.
Truy cập một giá trị của bản ghi
Để truy cập các trường và giá trị của một bản ghi cụ thể, nên sử dụng cú pháp sau.
Cú pháp
#recordname.Fieldname
Thông số
recordname - Đây là tên được đặt cho bản ghi.
Fieldname - Đây là tên của trường cần được truy cập.
Giá trị trả lại
Giá trị được gán cho trường.
Ví dụ
-module(helloworld).
-export([start/0]).
-record(person, {name = "", id}).
start() ->
P = #person{name = "John",id = 1},
io:fwrite("~p~n",[P#person.id]),
io:fwrite("~p~n",[P#person.name]).
Đầu ra
Kết quả của chương trình trên như sau.
1
“John”
Cập nhật giá trị của bản ghi
Việc cập nhật giá trị bản ghi được thực hiện bằng cách thay đổi giá trị thành một trường cụ thể và sau đó gán bản ghi cho một tên biến mới. Cú pháp chung và ví dụ được đưa ra bên dưới.
Cú pháp
#recordname.Fieldname = newvalue
Thông số
recordname - Đây là tên được đặt cho bản ghi.
Fieldname - Đây là tên của trường cần được truy cập.
newvalue - Đây là giá trị mới cần được gán cho trường.
Giá trị trả lại
Bản ghi mới với các giá trị mới được gán cho các trường.
Ví dụ
-module(helloworld).
-export([start/0]).
-record(person, {name = "", id}).
start() ->
P = #person{name = "John",id = 1},
P1 = P#person{name = "Dan"},
io:fwrite("~p~n",[P1#person.id]),
io:fwrite("~p~n",[P1#person.name]).
Đầu ra
Kết quả của chương trình trên như sau:
1
“Dan”
Bản ghi lồng nhau
Erlang cũng có cơ sở để có các bản ghi lồng nhau. Ví dụ sau cho thấy cách tạo các bản ghi lồng nhau này.
Ví dụ
-module(helloworld).
-export([start/0]).
-record(person, {name = "", address}).
-record(employee, {person, id}).
start() ->
P = #employee{person = #person{name = "John",address = "A"},id = 1},
io:fwrite("~p~n",[P#employee.id]).
Trong ví dụ trên, cần lưu ý những điều sau:
Đầu tiên chúng tôi tạo bản ghi của một người có các giá trị trường là tên và địa chỉ.
Sau đó, chúng tôi xác định một bản ghi nhân viên có người là một trường và một trường bổ sung được gọi là id.
Đầu ra
Kết quả của chương trình trên như sau.
1
Xử lý ngoại lệ được yêu cầu trong bất kỳ ngôn ngữ lập trình nào để xử lý các lỗi thời gian chạy để có thể duy trì luồng ứng dụng bình thường. Exception thường làm gián đoạn luồng thông thường của ứng dụng, đó là lý do tại sao chúng ta cần sử dụng xử lý Exception trong ứng dụng của mình.
Thông thường khi một ngoại lệ hoặc lỗi xảy ra trong Erlang, thông báo sau sẽ được hiển thị.
{"init terminating in do_boot", {undef,[{helloworld,start,[],[]},
{init,start_it,1,[]},{init,start_em,1,[]}]}}
Crash dump sẽ được ghi vào -
erl_crash.dump
init terminating in do_boot ()
Ở Erlang, có 3 loại ngoại lệ -
Error - Gọi điện erlang:error(Reason)sẽ kết thúc quá trình thực thi trong quy trình hiện tại và bao gồm một dấu vết ngăn xếp của các hàm cuối cùng được gọi với các đối số của chúng khi bạn bắt gặp nó. Đây là những loại ngoại lệ gây ra lỗi thời gian chạy ở trên.
Exists- Có hai loại lối ra: lối ra 'bên trong' và lối ra 'bên ngoài'. Các lối ra bên trong được kích hoạt bằng cách gọi hàmexit/1và làm cho quá trình hiện tại ngừng thực thi. Các lối ra bên ngoài được gọi bằngexit/2 và phải thực hiện với nhiều quy trình trong khía cạnh đồng thời của Erlang.
Throw- Một cú ném là một lớp ngoại lệ được sử dụng cho các trường hợp mà người lập trình có thể xử lý. So với các lần thoát và lỗi, chúng không thực sự mang lại bất kỳ 'sự cố quá trình nào!' ý định đằng sau chúng, nhưng đúng hơn là chúng kiểm soát luồng. Khi bạn sử dụng ném trong khi mong đợi lập trình viên xử lý chúng, bạn nên ghi lại việc sử dụng chúng trong một mô-đun sử dụng chúng.
A try ... catch là một cách để đánh giá một biểu thức trong khi cho phép bạn xử lý trường hợp thành công cũng như các lỗi gặp phải.
Cú pháp chung của biểu thức try catch như sau.
Cú pháp
try Expression of
SuccessfulPattern1 [Guards] ->
Expression1;
SuccessfulPattern2 [Guards] ->
Expression2
catch
TypeOfError:ExceptionPattern1 ->
Expression3;
TypeOfError:ExceptionPattern2 ->
Expression4
end
Biểu thức ở giữa try and ofđược cho là được bảo vệ. Điều này có nghĩa là bất kỳ loại ngoại lệ nào xảy ra trong cuộc gọi đó sẽ bị bắt. Các mẫu và biểu thức ở giữatry ... of and catch hành xử theo cách giống hệt như một case ... of.
Cuối cùng là phần bắt - ở đây, bạn có thể thay thế TypeOfErrorbằng một trong hai lỗi, ném hoặc thoát, đối với từng loại tương ứng mà chúng ta đã thấy trong chương này. Nếu không có loại nào được cung cấp, thì một lần ném được giả định.
Sau đây là một số lỗi và lý do lỗi trong Erlang -
lỗi | Loại lỗi |
---|---|
badarg | Lập luận tồi. Đối số có kiểu dữ liệu sai hoặc được định dạng sai. |
badarith | Đối số sai trong một biểu thức số học. |
{badmatch, V} | Đánh giá biểu thức đối sánh không thành công. Giá trị V không khớp. |
function_clause | Không tìm thấy mệnh đề hàm phù hợp khi đánh giá một lệnh gọi hàm. |
{case_clause, V} | Không tìm thấy nhánh phù hợp khi đánh giá một biểu thức chữ hoa chữ thường. Giá trị V không khớp. |
mệnh đề if | Không tìm thấy nhánh đúng khi đánh giá biểu thức if. |
{try_clause, V} | Không tìm thấy nhánh phù hợp khi đánh giá phần của một biểu thức thử. Giá trị V không khớp. |
undef | Không thể tìm thấy hàm khi đánh giá một lệnh gọi hàm .. |
{badfun, F} | Có gì đó không ổn với điểm F vui nhộn |
{tính xấu, F} | Một niềm vui được áp dụng cho số lượng đối số sai. F mô tả niềm vui và các lập luận. |
timeout_value | Giá trị thời gian chờ trong biểu thức nhận.. after được đánh giá thành giá trị khác với số nguyên hoặc vô hạn. |
noproc | Đang cố gắng liên kết với một quy trình không tồn tại. |
Sau đây là một ví dụ về cách những ngoại lệ này có thể được sử dụng và cách mọi thứ được thực hiện.
Hàm đầu tiên tạo ra tất cả các loại ngoại lệ có thể có.
Sau đó, chúng tôi viết một hàm wrapper để gọi generate_exception trong một biểu thức try ... catch.
Thí dụ
-module(helloworld).
-compile(export_all).
generate_exception(1) -> a;
generate_exception(2) -> throw(a);
generate_exception(3) -> exit(a);
generate_exception(4) -> {'EXIT', a};
generate_exception(5) -> erlang:error(a).
demo1() ->
[catcher(I) || I <- [1,2,3,4,5]].
catcher(N) ->
try generate_exception(N) of
Val -> {N, normal, Val}
catch
throw:X -> {N, caught, thrown, X};
exit:X -> {N, caught, exited, X};
error:X -> {N, caught, error, X}
end.
demo2() ->
[{I, (catch generate_exception(I))} || I <- [1,2,3,4,5]].
demo3() ->
try generate_exception(5)
catch
error:X ->
{X, erlang:get_stacktrace()}
end.
lookup(N) ->
case(N) of
1 -> {'EXIT', a};
2 -> exit(a)
end.
Nếu chúng ta chạy chương trình dưới dạng helloworld: demo (). , chúng ta sẽ nhận được kết quả sau:
Đầu ra
[{1,normal,a},
{2,caught,thrown,a},
{3,caught,exited,a},
{4,normal,{'EXIT',a}},
{5,caught,error,a}]
Macro thường được sử dụng để thay thế mã nội tuyến. Trong Erlang, macro được định nghĩa thông qua các câu lệnh sau.
- -define (Hằng số, Thay thế).
- -define (Func (Var1, Var2, .., Var), Replacement).
Sau đây là một ví dụ về macro sử dụng cú pháp đầu tiên:
Thí dụ
-module(helloworld).
-export([start/0]).
-define(a,1).
start() ->
io:fwrite("~w",[?a]).
Từ chương trình trên, bạn có thể thấy rằng macro được mở rộng bằng cách sử dụng dấu '?' Biểu tượng. Hằng số được thay thế bằng giá trị được xác định trong macro.
Đầu ra của chương trình trên sẽ là:
Đầu ra
1
Ví dụ về macro sử dụng lớp hàm như sau:
Thí dụ
-module(helloworld).
-export([start/0]).
-define(macro1(X,Y),{X+Y}).
start() ->
io:fwrite("~w",[?macro1(1,2)]).
Đầu ra của chương trình trên sẽ là:
Đầu ra
{3}
Các câu lệnh bổ sung sau đây có sẵn cho macro:
undef(Macro)- Hoàn tác xác định macro; sau đó bạn không thể gọi macro.
ifdef(Macro) - Chỉ đánh giá các dòng sau khi Macro đã được xác định.
ifndef(Macro) - Chỉ đánh giá các dòng sau nếu Macro là không xác định.
else- Được phép sau câu lệnh ifdef hoặc ifndef. Nếu điều kiện sai, các câu lệnh sau khác được đánh giá.
endif - Đánh dấu phần cuối của một câu lệnh ifdef hoặc ifndef.
Khi sử dụng các câu lệnh trên, nó nên được sử dụng theo cách thích hợp như trong chương trình sau.
-ifdef(<FlagName>).
-define(...).
-else.
-define(...).
-endif.
Tệp tiêu đề giống như tệp bao gồm trong bất kỳ ngôn ngữ lập trình nào khác. Nó rất hữu ích để chia các mô-đun thành các tệp khác nhau và sau đó truy cập các tệp tiêu đề này thành các chương trình riêng biệt. Để xem các tệp tiêu đề đang hoạt động, hãy xem một trong những ví dụ về bản ghi trước đó của chúng tôi.
Đầu tiên hãy tạo một tệp có tên user.hrl và thêm mã sau -
-record(person, {name = "", id}).
Bây giờ trong tệp chương trình chính của chúng ta, hãy thêm đoạn mã sau:
Thí dụ
-module(helloworld).
-export([start/0]).
-include("user.hrl").
start() ->
P = #person{name = "John",id = 1},
io:fwrite("~p~n",[P#person.id]),
io:fwrite("~p~n",[P#person.name]).
Như bạn có thể thấy từ chương trình trên, chúng tôi thực sự chỉ bao gồm tệp user.hrl tự động chèn –record mã trong đó.
Nếu bạn thực hiện chương trình trên, bạn sẽ nhận được kết quả sau.
Đầu ra
1
“John”
Bạn cũng có thể làm điều tương tự với macro, bạn có thể xác định macro bên trong tệp tiêu đề và tham chiếu nó trong tệp chính. Hãy xem một ví dụ về điều này -
Đầu tiên hãy tạo một tệp có tên user.hrl và thêm mã sau -
-define(macro1(X,Y),{X+Y}).
Bây giờ trong tệp chương trình chính của chúng ta, hãy thêm đoạn mã sau:
Thí dụ
-module(helloworld).
-export([start/0]).
-include("user.hrl").
start() ->
io:fwrite("~w",[?macro1(1,2)]).
Nếu bạn thực hiện chương trình trên, bạn sẽ nhận được kết quả sau:
Đầu ra
{3}
Trước khi một mô-đun Erlang được biên dịch, nó sẽ được xử lý tự động bởi Bộ tiền xử lý Erlang. Bộ tiền xử lý mở rộng bất kỳ macro nào có thể có trong tệp nguồn và chèn bất kỳ tệp bao gồm cần thiết nào.
Thông thường, bạn sẽ không cần phải xem đầu ra của bộ tiền xử lý, nhưng trong những trường hợp ngoại lệ (ví dụ: khi gỡ lỗi macro bị lỗi), bạn có thể muốn lưu đầu ra của bộ tiền xử lý. Để xem kết quả của việc xử lý trước mô-đunsome_module.erl đưa ra lệnh hệ điều hành shell.
erlc -P some_module.erl
Ví dụ: giả sử nếu chúng ta có tệp mã sau:
Thí dụ
-module(helloworld).
-export([start/0]).
-include("user.hrl").
start() ->
io:fwrite("~w",[?macro1(1,2)]).
Và nếu chúng ta thực hiện lệnh sau từ dòng lệnh:
erlc –P helloworld.erl
Một tệp được gọi là helloworld.Psẽ được tạo. Nếu bạn mở tệp này, bạn sẽ thấy nội dung sau đây là nội dung mà bộ tiền xử lý sẽ biên dịch.
-file("helloworld.erl", 1). -module(helloworld).
-export([start/0]).
-file("user.hrl", 1).
-file("helloworld.erl", 3).
start() ->
io:fwrite("~w", [{1 + 2}]).
Các mẫu trông giống như các thuật ngữ - chúng có thể là các chữ đơn giản như nguyên tử và số, hợp chất như bộ giá trị và danh sách, hoặc hỗn hợp của cả hai. Chúng cũng có thể chứa các biến, là các chuỗi chữ và số bắt đầu bằng chữ in hoa hoặc dấu gạch dưới. Một "biến ẩn danh" đặc biệt, _ (dấu gạch dưới) được sử dụng khi bạn không quan tâm đến giá trị được so khớp và sẽ không sử dụng nó.
Một mẫu phù hợp nếu nó có cùng "hình dạng" với thuật ngữ được đối sánh và các nguyên tử gặp phải giống nhau. Ví dụ: các trận đấu sau thành công:
- B = 1.
- 2 = 2.
- {ok, C} = {ok, 40}.
- [H | T] = [1, 2, 3,4].
Lưu ý rằng trong ví dụ thứ tư, dấu (|) biểu thị phần đầu và phần đuôi của danh sách như được mô tả trong Điều khoản. Cũng lưu ý rằng bên tay trái phải khớp với bên tay phải, đây là trường hợp bình thường của các mẫu.
Các ví dụ sau về khớp mẫu sẽ không thành công.
- 1 = 2.
- {ok, A} = {fail, "Không biết câu hỏi"}.
- [H | T] = [].
Trong trường hợp của toán tử đối sánh mẫu, lỗi sẽ tạo ra lỗi và quá trình sẽ thoát ra. Làm thế nào điều này có thể bị mắc kẹt và xử lý được bao gồm trong Lỗi. Các mẫu được sử dụng để chọn mệnh đề của một hàm sẽ được thực thi.
Bảo vệ là cấu trúc mà chúng ta có thể sử dụng để tăng sức mạnh của khớp mẫu. Sử dụng bảo vệ, chúng ta có thể thực hiện các phép thử và so sánh đơn giản trên các biến trong một mẫu.
Cú pháp chung của câu lệnh bảo vệ như sau:
function(parameter) when condition ->
Ở đâu,
Function(parameter) - Đây là phần khai báo hàm được sử dụng trong điều kiện bảo vệ.
Parameter - Nói chung điều kiện bảo vệ dựa trên tham số.
Condition - Điều kiện cần được đánh giá để xem chức năng có nên được thực thi hay không.
Câu lệnh when phải được sử dụng khi điều kiện bảo vệ được chỉ định.
Hãy xem một ví dụ nhanh về cách sử dụng lính canh -
Thí dụ
-module(helloworld).
-export([display/1,start/0]).
display(N) when N > 10 ->
io:fwrite("greater then 10");
display(N) when N < 10 -> io:fwrite("Less
than 10").
start() ->
display(11).
Những điều sau đây cần được lưu ý về ví dụ trên:
Chức năng hiển thị được xác định cùng với một bảo vệ. Khai báo hiển thị đầu tiên có bảo vệ khi tham số N lớn hơn 10. Vì vậy, nếu tham số lớn hơn 10, hàm đó sẽ được gọi.
Chức năng hiển thị được định nghĩa lại, nhưng lần này với mức bảo vệ nhỏ hơn 10. Bằng cách này, bạn có thể xác định cùng một chức năng nhiều lần, mỗi lần có một điều kiện bảo vệ riêng biệt.
Kết quả của chương trình trên sẽ như sau:
Đầu ra
greater than 10
Các điều kiện bảo vệ cũng có thể được sử dụng cho if else và casecác câu lệnh. Hãy xem cách chúng ta có thể thực hiện các hoạt động bảo vệ trên các câu lệnh này.
Bảo vệ cho Câu lệnh 'if'
Các lệnh bảo vệ cũng có thể được sử dụng cho các câu lệnh if để chuỗi các câu lệnh được thực thi dựa trên điều kiện bảo vệ. Hãy xem làm thế nào chúng ta có thể đạt được điều này.
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
N = 9,
if
N > 10 ->
io:fwrite("N is greater than 10");
true ->
io:fwrite("N is less than 10")
end.
Những điều sau đây cần được lưu ý về ví dụ trên:
Hàm bảo vệ được sử dụng cùng với câu lệnh if. Nếu hàm bảo vệ đánh giá là true, thì câu lệnh “N lớn hơn 10” được hiển thị.
Nếu hàm bảo vệ đánh giá là sai, thì câu lệnh “N nhỏ hơn 10” được hiển thị.
Kết quả của chương trình trên sẽ như sau:
Đầu ra
N is less than 10
Bảo vệ cho Tuyên bố 'trường hợp'
Các lệnh bảo vệ cũng có thể được sử dụng cho các câu lệnh trường hợp để chuỗi các câu lệnh được thực thi dựa trên điều kiện bảo vệ. Hãy xem làm thế nào chúng ta có thể đạt được điều này.
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
A = 9,
case A of {A} when A>10 ->
io:fwrite("The value of A is greater than 10"); _ ->
io:fwrite("The value of A is less than 10")
end.
Những điều sau đây cần được lưu ý về ví dụ trên:
Chức năng bảo vệ được sử dụng cùng với câu lệnh trường hợp. Nếu hàm bảo vệ đánh giá là true, thì câu lệnh “Giá trị của A lớn hơn 10” được hiển thị.
Nếu hàm bảo vệ đánh giá bất kỳ điều gì khác, thì câu lệnh “Giá trị của A nhỏ hơn 10” được hiển thị.
Kết quả của chương trình trên sẽ như sau:
Đầu ra
The value of A is less than 10
Nhiều điều kiện bảo vệ
Nhiều điều kiện bảo vệ cũng có thể được chỉ định cho một chức năng. Cú pháp chung của câu lệnh bảo vệ với nhiều điều kiện bảo vệ được đưa ra dưới đây:
function(parameter) when condition1 , condition1 , .. conditionN ->
Ở đâu,
Function(parameter) - Đây là khai báo hàm đã sử dụng điều kiện bảo vệ.
Parameter - Nói chung điều kiện bảo vệ dựa trên tham số.
condition1, condition1, .. conditionN - Đây là nhiều điều kiện bảo vệ được áp dụng cho các chức năng.
Câu lệnh when phải được sử dụng khi điều kiện bảo vệ được chỉ định.
Hãy xem một ví dụ nhanh về cách có thể sử dụng nhiều bảo vệ -
Thí dụ
-module(helloworld).
-export([display/1,start/0]).
display(N) when N > 10 , is_integer(N) ->
io:fwrite("greater then 10");
display(N) when N < 10 ->
io:fwrite("Less than 10").
start() ->
display(11).
Điểm sau đây cần được lưu ý về ví dụ trên:
Bạn sẽ nhận thấy rằng đối với khai báo hàm hiển thị đầu tiên, ngoài điều kiện cho N> 10, điều kiện cho is_integercũng được chỉ định. Vì vậy, chỉ khi giá trị của N là số nguyên và lớn hơn 10, hàm này sẽ được thực hiện.
Kết quả của chương trình trên sẽ như sau:
Đầu ra
Greater than 10
BIF là các hàm được tích hợp sẵn trong Erlang. Họ thường làm những công việc không thể lập trình được trong Erlang. Ví dụ: không thể chuyển một danh sách thành một bộ hoặc để tìm ngày giờ hiện tại. Để thực hiện một hoạt động như vậy, chúng tôi gọi là BIF.
Hãy lấy một ví dụ về cách BIF được sử dụng -
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite("~p~n",[tuple_to_list({1,2,3})]),
io:fwrite("~p~n",[time()]).
Những điều sau đây cần được lưu ý về ví dụ trên:
Trong ví dụ đầu tiên, chúng tôi đang sử dụng BIF được gọi là tuple_to_list để chuyển đổi một tuple thành một danh sách.
Trong hàm BIF thứ hai, chúng tôi đang sử dụng time function để xuất thời gian hệ thống.
Kết quả của chương trình trên sẽ như sau:
Đầu ra
[1,2,3]
{10,54,56}
Hãy xem xét một số hàm BIF khác có sẵn trong Erlang.
Sr.No. | Chức năng & Mô tả BIF |
---|---|
1 | ngày Phương thức này trả về ngày hệ thống hiện tại. |
2 | byte_size Phương thức này trả về số byte có trong một chuỗi Bit. |
3 | thành phần Phương thức trả về phần tử thứ N trong bộ tuple. |
4 | Phao nổi Phương thức này trả về giá trị float của một số cụ thể. |
5 | được Phương thức trả về từ điển quy trình dưới dạng danh sách. |
6 | đặt Phương pháp này được sử dụng để đặt một key,value ghép nối trong từ điển quy trình. |
7 | giờ địa phương Phương thức được sử dụng để cung cấp ngày và giờ cục bộ trong hệ thống. |
số 8 | ký ức Trả về danh sách chứa thông tin về bộ nhớ được cấp phát động bởi trình giả lập Erlang. |
9 | hiện nay Phương thức này trả về tuple {MegaSecs, Secs, MicroSecs} là thời gian đã trôi qua kể từ 00:00 GMT, ngày 1 tháng 1 năm 1970. |
10 | cổng Trả về danh sách tất cả các cổng trên nút cục bộ |
11 | quy trình Trả về danh sách các số nhận dạng quy trình tương ứng với tất cả các quy trình hiện đang tồn tại trên nút cục bộ. |
12 | thời gian phổ quát Trả về ngày và giờ hiện tại theo Phối hợp Giờ Quốc tế (UTC). |
Sử dụng cấu trúc dữ liệu được gọi là nhị phân để lưu trữ số lượng lớn dữ liệu thô. Binaries lưu trữ dữ liệu theo cách hiệu quả hơn nhiều so với trong danh sách hoặc bộ dữ liệu và hệ thống thời gian chạy được tối ưu hóa cho đầu vào và đầu ra hiệu quả của các mã nhị phân.
Dấu hai chấm được viết và in dưới dạng chuỗi số nguyên hoặc chuỗi, được đặt trong dấu ngoặc kép nhỏ hơn và lớn hơn.
Sau đây là một ví dụ về mã nhị phân trong Erlang:
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
io:fwrite("~p~n",[<<5,10,20>>]),
io:fwrite("~p~n",[<<"hello">>]).
Khi chạy chương trình trên, chúng ta sẽ nhận được kết quả như sau.
Đầu ra
<<5,10,20>>
<<"hello">>
Hãy xem xét các hàm Erlang có sẵn để làm việc với Binaries -
Sr.No. | Phương pháp & Mô tả |
---|---|
1 | list_to_binary Phương pháp này được sử dụng để chuyển đổi một danh sách hiện có thành một danh sách các tệp nhị phân. |
2 | split_binary Phương pháp này được sử dụng để tách danh sách nhị phân dựa trên vị trí chỉ mục được chỉ định. |
3 | term_to_binary Phương pháp này được sử dụng để chuyển đổi một thuật ngữ sang hệ nhị phân. |
4 | is_binary Phương pháp này được sử dụng để kiểm tra xem một chuỗi bit có thực sự là một giá trị nhị phân hay không. |
5 | binary_part Phương thức này được sử dụng để trích xuất một phần của chuỗi nhị phân |
6 | binary_to_float Phương thức này được sử dụng để chuyển đổi một giá trị nhị phân thành một giá trị thực. |
7 | binary_to_integer Phương thức này được sử dụng để chuyển đổi một giá trị nhị phân thành một giá trị nguyên. |
số 8 | binary_to_list Phương pháp này được sử dụng để chuyển đổi một giá trị nhị phân thành một danh sách. |
9 | binary_to_atom Phương pháp này được sử dụng để chuyển đổi một giá trị nhị phân thành một nguyên tử. |
Funs được sử dụng để xác định các hàm ẩn danh trong Erlang. Cú pháp chung của một hàm ẩn danh được đưa ra dưới đây:
Cú pháp
F = fun (Arg1, Arg2, ... ArgN) ->
...
End
Ở đâu
F - Đây là tên biến được gán cho hàm ẩn danh.
Arg1, Arg2, ... ArgN - Đây là các đối số được chuyển cho hàm ẩn danh.
Ví dụ sau đây cho thấy cách hàm ẩn danh có thể được sử dụng.
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
A = fun() -> io:fwrite("Hello") end,
A().
Những điều sau đây cần được lưu ý về chương trình trên.
Hàm vô danh được gán cho biến A.
Hàm ẩn danh qua biến A ().
Khi chạy chương trình trên, chúng ta sẽ nhận được kết quả như sau.
“Hello”
Một ví dụ khác về hàm ẩn danh như sau, nhưng đây là với việc sử dụng các tham số.
-module(helloworld).
-export([start/0]).
start() ->
A = fun(X) ->
io:fwrite("~p~n",[X])
end,
A(5).
Khi chạy chương trình trên, chúng ta sẽ nhận được kết quả như sau.
Đầu ra
5
Sử dụng các biến
Hàm Anonymous có khả năng truy cập các biến nằm ngoài phạm vi của hàm ẩn danh. Hãy xem một ví dụ về điều này -
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
B = 6,
A = fun(X) ->
io:fwrite("~p~n",[X]),
io:fwrite("~p~n",[B])
end,
A(5).
Những điều sau đây cần được lưu ý về chương trình trên.
Biến B nằm ngoài phạm vi của hàm ẩn danh.
Hàm ẩn danh vẫn có thể truy cập vào biến được xác định trong phạm vi toàn cục.
Khi chạy chương trình trên, chúng ta sẽ nhận được kết quả như sau.
Đầu ra
5
6
Các chức năng trong Chức năng
Một trong những khía cạnh mạnh mẽ nhất khác của các hàm bậc cao là bạn có thể định nghĩa một hàm trong một hàm. Hãy xem một ví dụ về cách chúng ta có thể đạt được điều này.
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
Adder = fun(X) -> fun(Y) -> io:fwrite("~p~n",[X + Y]) end end,
A = Adder(6),
A(10).
Những điều sau đây cần được lưu ý về chương trình trên.
Adder là một hàm bậc cao hơn được định nghĩa là fun (X).
Hàm Adder fun (X) có tham chiếu đến một hàm fun (Y) khác.
Khi chạy chương trình trên, chúng ta sẽ nhận được kết quả như sau.
Đầu ra
16
Mức độ chi tiết của đồng thời trong Erlang là một quá trình. Quy trình là một hoạt động / nhiệm vụ chạy đồng thời và độc lập với các quy trình khác. Các quy trình này trong Erlang khác với các quy trình và luồng mà hầu hết mọi người đều quen thuộc. Các quy trình Erlang có dung lượng nhẹ, hoạt động trong (bộ nhớ) cách ly với các quy trình khác và được lên lịch bởi Máy ảo (VM) của Erlang. Thời gian tạo quy trình rất thấp, dung lượng bộ nhớ của một quy trình vừa sinh ra là rất nhỏ và một máy ảo Erlang duy nhất có thể có hàng triệu quy trình đang chạy.
Một quy trình được tạo ra với sự trợ giúp của phương pháp đẻ trứng. Cú pháp chung của phương thức được đưa ra dưới đây.
Cú pháp
spawn(Module, Name, Args)
Thông số
Module - Đây là một giá trị nguyên tử được xác định trước, phải là? MODULE.
Name - Đây là tên của hàm sẽ được gọi khi tiến trình được xác định.
Args - Đây là các đối số cần được gửi đến hàm.
Giá trị trả lại
Trả về id quy trình của quy trình mới được tạo.
Ví dụ
Ví dụ về phương pháp đẻ trứng được hiển thị trong chương trình sau.
-module(helloworld).
-export([start/0, call/2]).
call(Arg1, Arg2) ->
io:format("~p ~p~n", [Arg1, Arg2]).
start() ->
Pid = spawn(?MODULE, call, ["hello", "process"]),
io:fwrite("~p",[Pid]).
Những điều sau đây cần được lưu ý về chương trình trên.
Một hàm được gọi là cuộc gọi được định nghĩa và sẽ được sử dụng để tạo quá trình.
Phương thức spawn gọi hàm gọi với các tham số hello và process.
Đầu ra
Khi chạy chương trình trên, chúng ta sẽ nhận được kết quả như sau.
<0.29.0>"hello" "process"
Bây giờ chúng ta hãy xem xét các chức năng khác có sẵn với các quy trình.
Sr.No. | Phương pháp & Mô tả |
---|---|
1 | is_pid Phương pháp này được sử dụng để xác định xem có tồn tại một id quy trình hay không. |
2 | is_process_alive Điều này được gọi là is_process_alive (Pid). Một Pid phải tham chiếu đến một tiến trình tại nút cục bộ. |
3 | pid_to_list Nó chuyển đổi một id quy trình thành một danh sách. |
4 | đã đăng ký Trả về một danh sách với tên của tất cả các quy trình đã đăng ký. |
5 | bản thân Một trong những BIF được sử dụng phổ biến nhất, trả về pid của các quá trình gọi. |
6 | Đăng ký Nó được sử dụng để đăng ký một tiến trình trong hệ thống. |
7 | ở đâu Nó được gọi là whereis (Tên). Trả về pid của quá trình đã được đăng ký với tên. |
số 8 | hủy đăng ký Điều này được sử dụng để hủy đăng ký một quy trình trong hệ thống. |
Để gửi email bằng Erlang, bạn cần sử dụng một gói có sẵn từ githubcho cùng. Liên kết github là -https://github.com/Vagabond/gen_smtp
Liên kết này chứa một smtp utilitycó thể được sử dụng để gửi email từ ứng dụng Erlang. Làm theo các bước để có thể gửi email từ Erlang
Step 1 - Tải xuống erl files từ github site. Các tệp sẽ được tải xuống thư mục nơihelloworld.erl ứng dụng cư trú.
Step 2 - Biên dịch tất cả smtp related files hiển thị trong danh sách sau bằng cách sử dụng erlc command. Các tệp sau đây cần được biên dịch.
- smtp_util
- gen_smtp_client
- gen_smtp_server
- gen_smtp_server_session
- binstr
- gen_smtp_application
- socket
Step 3 - Đoạn mã sau có thể được viết để gửi email bằng smtp.
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
gen_smtp_client:send({"[email protected]", ["[email protected]"], "Subject: testing"},
[{relay, "smtp.gmail.com"}, {ssl, true}, {username, "[email protected]"},
{password, "senderpassword"}]).
Những điều sau đây cần lưu ý về chương trình trên
Hàm smtp trên đang được sử dụng cùng với máy chủ smtp có sẵn từ google.
Vì chúng tôi muốn gửi bằng smtp an toàn, chúng tôi chỉ định tham số ssl là true.
Bạn cần chỉ định rơle là smtp.gmail.com.
Bạn cần phải đề cập đến tên người dùng và mật khẩu có quyền truy cập để gửi email.
Sau khi bạn cấu hình tất cả các cài đặt trên và thực thi chương trình, người nhận sẽ nhận được email thành công.
Erlang có khả năng kết nối với các cơ sở dữ liệu truyền thống như SQL Server và Oracle. Erlang có mộtinbuilt odbc library có thể được sử dụng để làm việc với cơ sở dữ liệu.
Kết nối cơ sở dữ liệu
Trong ví dụ của chúng tôi, chúng tôi sẽ sử dụng Microsoft SQL Server. Trước khi kết nối với cơ sở dữ liệu Microsoft SQL Server, hãy đảm bảo rằng các con trỏ sau được chọn.
Bạn đã tạo một cơ sở dữ liệu TESTDB.
Bạn đã tạo một bảng EMPLOYEE trong TESTDB.
Bảng này có các trường FIRST_NAME, LAST_NAME, AGE, SEX và THU NHẬP.
ID người dùng "testuser" và mật khẩu "test123" được đặt để truy cập TESTDB.
Đảm bảo rằng bạn đã tạo ODBC DSN được gọi là usersqlserver tạo kết nối ODBC với cơ sở dữ liệu
Thiết lập kết nối
Để thiết lập kết nối với cơ sở dữ liệu, có thể sử dụng ví dụ mã sau.
Example
-module(helloworld).
-export([start/0]).
start() ->
odbc:start(),
{ok, Ref} = odbc:connect("DSN = usersqlserver;UID = testuser;PWD = test123", []),
io:fwrite("~p",[Ref]).
Kết quả của chương trình trên như sau:
Output
<0.33.0>
Những điều sau đây cần được lưu ý về chương trình trên.
Phương thức bắt đầu của thư viện odbc được sử dụng để chỉ ra sự bắt đầu của hoạt động cơ sở dữ liệu.
Phương thức kết nối yêu cầu DSN, tên người dùng và mật khẩu để kết nối.
Tạo bảng cơ sở dữ liệu
Bước tiếp theo sau khi kết nối với cơ sở dữ liệu là tạo các bảng trong cơ sở dữ liệu của chúng tôi. Ví dụ sau đây cho thấy cách tạo một bảng trong cơ sở dữ liệu bằng Erlang.
Example
-module(helloworld).
-export([start/0]).
start() ->
odbc:start(),
{ok, Ref} = odbc:connect("DSN = usersqlserver; UID = testuser;PWD = test123, []),
odbc:sql_query(Ref, "CREATE TABLE EMPLOYEE (FIRSTNAME char varying(20),
LASTNAME char varying(20), AGE integer, SEX char(1), INCOME integer)")
Nếu bây giờ bạn kiểm tra cơ sở dữ liệu, bạn sẽ thấy một bảng có tên EMPLOYEE sẽ được tạo ra.
Chèn Bản ghi vào Cơ sở dữ liệu
Nó được yêu cầu khi bạn muốn tạo bản ghi của mình vào một bảng cơ sở dữ liệu.
Ví dụ sau sẽ chèn một bản ghi trong bảng nhân viên. Nếu bảng được cập nhật thành công, bản ghi và câu lệnh sẽ trả về giá trị của bản ghi được cập nhật và số lượng bản ghi đã được cập nhật.
Example
-module(helloworld).
-export([start/0]).
start() ->
odbc:start(),
{ok, Ref} = odbc:connect("DSN = usersqlserver; UID = testuser;PWD = test123", []),
io:fwrite("~p",[odbc:sql_query(Ref,
"INSERT INTO EMPLOYEE VALUES('Mac', 'Mohan', 20, 'M', 2000)")]).
Đầu ra của chương trình trên sẽ là:
Output
{updated,1}
Tìm nạp Bản ghi từ Cơ sở dữ liệu
Erlang cũng có khả năng lấy các bản ghi từ cơ sở dữ liệu. Điều này được thực hiện thông quasql_query method.
Một ví dụ được hiển thị trong chương trình sau:
Example
-module(helloworld).
-export([start/0]).
start() ->
odbc:start(),
{ok, Ref} = odbc:connect("DSN = usersqlserver; UID = testuser;PWD = test123", []),
io:fwrite("~p",[odbc:sql_query(Ref, "SELECT * FROM EMPLOYEE") ]).
Kết quả của chương trình trên sẽ như sau:
Output
{selected,["FIRSTNAME","LASTNAME","AGE","SEX","INCOME"],
[{"Mac","Mohan",20,"M",2000}]}
Vì vậy, bạn có thể thấy rằng lệnh chèn trong phần cuối cùng đã hoạt động và lệnh select trả về đúng dữ liệu.
Tìm nạp bản ghi từ cơ sở dữ liệu dựa trên các tham số
Erlang cũng có khả năng lấy các bản ghi từ cơ sở dữ liệu dựa trên các tiêu chí bộ lọc nhất định.
Một ví dụ như sau:
Example
-module(helloworld).
-export([start/0]).
start() ->
odbc:start(),
{ok, Ref} = odbc:connect("DSN=usersqlserver; UID=testuser;PWD=test123", []),
io:fwrite("~p",[ odbc:param_query(Ref, "SELECT * FROM EMPLOYEE WHERE SEX=?",
[{{sql_char, 1}, ["M"]}])]).
Đầu ra của chương trình trên sẽ là:
Output
{selected,["FIRSTNAME","LASTNAME","AGE","SEX","INCOME"],
[{"Mac","Mohan",20,"M",2000}]}
Cập nhật hồ sơ từ cơ sở dữ liệu
Erlang cũng có khả năng cập nhật các bản ghi từ cơ sở dữ liệu.
Một ví dụ cho điều tương tự như sau:
Example
-module(helloworld).
-export([start/0]).
start() ->
odbc:start(),
{ok, Ref} = odbc:connect("DSN = usersqlserver; UID = testuser;PWD = test123", []),
io:fwrite("~p",[ odbc:sql_query(Ref, "
UPDATE EMPLOYEE SET AGE = 5 WHERE INCOME= 2000")]).
Đầu ra của chương trình trên sẽ là:
Output
{updated,1}
Xóa bản ghi khỏi cơ sở dữ liệu
Erlang cũng có khả năng xóa các bản ghi khỏi cơ sở dữ liệu.
Một ví dụ cho điều tương tự như sau:
Example
-module(helloworld).
-export([start/0]).
start() ->
odbc:start(),
{ok, Ref} = odbc:connect("DSN = usersqlserver; UID = testuser;PWD = test123", []),
io:fwrite("~p",[ odbc:sql_query(Ref, "DELETE EMPLOYEE WHERE INCOME= 2000")]).
Kết quả của chương trình trên sẽ như sau:
Output
{updated,1}
Cấu trúc bảng
Erlang cũng có khả năng mô tả cấu trúc bảng.
Một ví dụ như sau:
Example
-module(helloworld).
-export([start/0]).
start() ->
odbc:start(),
{ok, Ref} = odbc:connect("DSN = usersqlserver; UID = testuser;PWD = test123", []),
io:fwrite("~p",[odbc:describe_table(Ref, "EMPLOYEE")]).
Kết quả của chương trình trên sẽ như sau:
Output
{ok,[{"FIRSTNAME",{sql_varchar,20}},
{"LASTNAME",{sql_varchar,20}},
{"AGE",sql_integer},
{"SEX",{sql_char,1}},
{"INCOME",sql_integer}]}
Bản ghi đếm
Erlang cũng có khả năng lấy tổng số bản ghi trong một bảng.
Một ví dụ cho điều tương tự được hiển thị trong chương trình sau.
Example
-module(helloworld).
-export([start/0]).
start() ->
odbc:start(),
{ok, Ref} = odbc:connect("DSN = usersqlserver; UID = sa;PWD = demo123", []),
io:fwrite("~p",[odbc:select_count(Ref, "SELECT * FROM EMPLOYEE")]).
Đầu ra của chương trình trên sẽ là:
{ok,1}
Trong Erlang, các cổng được sử dụng để giao tiếp giữa các chương trình khác nhau. Ổ cắm là một điểm cuối giao tiếp cho phép các máy giao tiếp qua Internet bằng cách sử dụng Giao thức Internet (IP).
Các loại giao thức được sử dụng trong các cổng
Có 2 loại giao thức có sẵn để giao tiếp. Một là UDP và một là TCP. UDP cho phép các ứng dụng gửi các tin nhắn ngắn (được gọi là datagram) cho nhau, nhưng không có gì đảm bảo việc gửi các tin nhắn này. Họ cũng có thể đến không theo thứ tự. Mặt khác, TCP cung cấp một luồng byte đáng tin cậy được phân phối theo thứ tự miễn là kết nối được thiết lập.
Hãy xem một ví dụ đơn giản về việc mở một cổng bằng UDP.
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
{ok, Socket} = gen_udp:open(8789),
io:fwrite("~p",[Socket]).
Những điều sau đây cần lưu ý về chương trình trên
Các gen_udp chứa các mô-đun trong Erlang được sử dụng cho giao tiếp UDP.
Đây 8789 là số cổng đang được mở ở Erlang. Bạn cần đảm bảo rằng số cổng này có sẵn và có thể sử dụng được.
Đầu ra của chương trình trên là:
#Port<0.376>
Gửi tin nhắn trên cổng
Khi cổng đã được mở, một thông báo có thể được gửi trên cổng. Điều này được thực hiện thông qua phương thức gửi. Hãy xem cú pháp và ví dụ sau.
Cú pháp
send(Socket, Address, Port, Packet)
Thông số
Socket - Đây là socket được tạo bằng lệnh gen_udp: open.
Address - Đây là địa chỉ máy để gửi tin nhắn đến.
port - Đây là cổng mà tin nhắn cần được gửi đi.
Packet - Đây là chi tiết gói tin hoặc tin nhắn cần được gửi đi.
Giá trị trả lại
Một tin nhắn ok sẽ được trả lại nếu tin nhắn được gửi đúng cách.
Ví dụ
-module(helloworld).
-export([start/0]).
start() ->
{ok, Socket} = gen_udp:open(8789),
io:fwrite("~p",[Socket]),
io:fwrite("~p",[gen_udp:send
(Socket,"localhost",8789,"Hello")]).
Đầu ra
Kết quả của chương trình trên sẽ như sau.
#Port<0.376>ok
Nhận tin nhắn trên cổng
Khi cổng đã được mở, một thông báo cũng có thể được nhận trên cổng. Điều này được thực hiện thông quarecv method. Hãy xem cú pháp và ví dụ sau.
Cú pháp
recv(Socket, length)
Thông số
Socket - Đây là socket được tạo bằng lệnh gen_udp: open.
Length - Đây là độ dài của tin nhắn cần được nhận.
Giá trị trả lại
Một tin nhắn ok sẽ được trả lại nếu tin nhắn được gửi đúng cách.
Ví dụ
-module(helloworld).
-export([start/0]).
start() ->
{ok, Socket} = gen_udp:open(8789),
io:fwrite("~p",[Socket]),
io:fwrite("~p",[gen_udp:send(Socket,"localhost",8789,"Hello")]),
io:fwrite("~p",[gen_udp:recv(Socket, 20)]).
Chương trình hoàn chỉnh
Rõ ràng là chúng ta không thể có cùng một tin nhắn gửi và nhận trong cùng một chương trình. Bạn cần xác định chúng trong các chương trình khác nhau. Vì vậy, hãy tạo đoạn mã sau để tạo một thành phần máy chủ lắng nghe thông báo và một thành phần máy khách gửi thông báo.
Thí dụ
-module(helloworld).
-export([start/0,client/1]).
start() ->
spawn(fun() -> server(4000) end).
server(Port) ->
{ok, Socket} = gen_udp:open(Port, [binary, {active, false}]),
io:format("server opened socket:~p~n",[Socket]),
loop(Socket).
loop(Socket) ->
inet:setopts(Socket, [{active, once}]),
receive
{udp, Socket, Host, Port, Bin} ->
io:format("server received:~p~n",[Bin]),
gen_udp:send(Socket, Host, Port, Bin),
loop(Socket)
end.
client(N) ->
{ok, Socket} = gen_udp:open(0, [binary]),
io:format("client opened socket=~p~n",[Socket]),
ok = gen_udp:send(Socket, "localhost", 4000, N), Value = receive
{udp, Socket, _, _, Bin} ->
io:format("client received:~p~n",[Bin]) after 2000 ->
0
end,
gen_udp:close(Socket),
Value.
Những điều sau đây cần được lưu ý về chương trình trên.
Chúng tôi xác định 2 chức năng, chức năng đầu tiên là máy chủ. Điều này sẽ được sử dụng để lắng nghe trên cổng 4000. Thứ hai là ứng dụng khách sẽ được sử dụng để gửi thông báo “Xin chào” đến thành phần máy chủ.
Vòng lặp nhận được sử dụng để đọc các tin nhắn được gửi trong vòng lặp xác định.
Đầu ra
Bây giờ bạn cần chạy chương trình từ 2 cửa sổ. Cửa sổ đầu tiên sẽ được sử dụng để chạy thành phần máy chủ bằng cách chạy mã sau trongerl command line window.
helloworld:start().
Thao tác này sẽ hiển thị kết quả sau trong cửa sổ dòng lệnh.
server opened socket:#Port<0.2314>
Bây giờ trong cửa sổ dòng lệnh erl thứ hai, hãy chạy lệnh sau.
Helloworld:client(“<<Hello>>”).
Khi bạn phát hành lệnh này, kết quả sau sẽ được hiển thị trong cửa sổ dòng lệnh đầu tiên.
server received:<<"Hello">>
Chương trình phân tán là những chương trình được thiết kế để chạy trên mạng máy tính và có thể điều phối các hoạt động của chúng chỉ bằng cách truyền thông điệp.
Có một số lý do tại sao chúng ta có thể muốn viết các ứng dụng phân tán. Dưới đây là một số trong số họ.
Performance - Chúng ta có thể làm cho các chương trình của mình chạy nhanh hơn bằng cách sắp xếp các phần khác nhau của chương trình được chạy song song trên các máy khác nhau.
Reliability- Chúng ta có thể tạo ra các hệ thống có khả năng chịu lỗi bằng cách cấu trúc hệ thống chạy trên một số máy. Nếu một máy bị lỗi, chúng ta có thể tiếp tục trên máy khác.
Scalability- Khi chúng ta mở rộng quy mô một ứng dụng, sớm hay muộn chúng ta cũng sẽ cạn kiệt khả năng của ngay cả chiếc máy mạnh nhất. Giai đoạn này chúng tôi phải bổ sung thêm máy móc để tăng thêm công suất. Thêm một máy mới phải là một hoạt động đơn giản không yêu cầu thay đổi lớn đối với kiến trúc ứng dụng.
Khái niệm trung tâm trong Erlang phân tán là nút. Một nút là một nút khép kín.
Hệ thống Erlang chứa một máy ảo hoàn chỉnh với không gian địa chỉ riêng và bộ quy trình riêng.
Hãy xem xét sự khác biệt methods được sử dụng cho Distributed Programming.
Sr.No. | Phương pháp & Mô tả |
---|---|
1 | đẻ trứng Điều này được sử dụng để tạo một quy trình mới và khởi tạo nó. |
2 | nút Điều này được sử dụng để xác định giá trị của nút mà tiến trình cần chạy. |
3 | đẻ trứng trên Node Điều này được sử dụng để tạo một tiến trình mới trên một nút. |
4 | is_alive Điều này trả về true nếu nút cục bộ còn sống và có thể là một phần của hệ thống phân tán. |
5 | spawnlink Điều này được sử dụng để tạo một liên kết quy trình mới trên một nút. |
OTP là viết tắt của Open Telecom Platform. Đó là một hệ điều hành ứng dụng và một tập hợp các thư viện và thủ tục được sử dụng để xây dựng các ứng dụng phân tán, có khả năng chịu lỗi, quy mô lớn. Nếu bạn muốn lập trình các ứng dụng của riêng mình bằng OTP, thì khái niệm trung tâm mà bạn sẽ thấy rất hữu ích là hành vi OTP. Một hành vi đóng gói các mẫu hành vi phổ biến - hãy nghĩ về nó như một khuôn khổ ứng dụng được tham số hóa bởi một mô-đun gọi lại.
Sức mạnh của OTP đến từ các thuộc tính như khả năng chịu lỗi, khả năng mở rộng, nâng cấp mã động, v.v., có thể được cung cấp bởi chính hành vi. Vì vậy, khái niệm cơ bản đầu tiên là tạo một thành phần máy chủ bắt chước những điều cơ bản của môi trường OTP, hãy cùng xem ví dụ sau.
Thí dụ
-module(server).
-export([start/2, rpc/2]).
start(Name, Mod) ->
register(Name, spawn(fun() -> loop(Name, Mod, Mod:init()) end)).
rpc(Name, Request) ->
Name ! {self(), Request},
receive
{Name, Response} -> Response
end.
loop(Name, Mod, State) ->
receive
{From, Request} ->
{Response, State1} = Mod:handle(Request, State),
From ! {Name, Response},
loop(Name, Mod, State1)
end.
Những điều sau đây cần được lưu ý về chương trình trên:
Quá trình này nếu được đăng ký với hệ thống bằng chức năng đăng ký.
Quá trình tạo ra một hàm vòng lặp để xử lý quá trình.
Bây giờ chúng ta hãy viết một chương trình khách sử dụng chương trình máy chủ.
Thí dụ
-module(name_server).
-export([init/0, add/2, whereis/1, handle/2]).
-import(server1, [rpc/2]).
add(Name, Place) -> rpc(name_server, {add, Name, Place}).
whereis(Name) -> rpc(name_server, {whereis, Name}).
init() -> dict:new().
handle({add, Name, Place}, Dict) -> {ok, dict:store(Name, Place, Dict)};
handle({whereis, Name}, Dict) -> {dict:find(Name, Dict), Dict}.
Mã này thực sự thực hiện hai nhiệm vụ. Nó phục vụ như một mô-đun gọi lại được gọi từ mã khung máy chủ, đồng thời, nó chứa các quy trình giao tiếp sẽ được gọi bởi máy khách. Quy ước OTP thông thường là kết hợp cả hai chức năng trong cùng một mô-đun.
Vì vậy, đây là cách chương trình trên cần được chạy -
Trong erl, trước tiên hãy chạy chương trình máy chủ bằng cách chạy lệnh sau.
server(name_server,name_server)
Bạn sẽ nhận được kết quả sau:
Đầu ra
true
Sau đó, chạy lệnh sau
name_server.add(erlang,”Tutorialspoint”).
Bạn sẽ nhận được kết quả sau:
Đầu ra
Ok
Sau đó, chạy lệnh sau:
name_server.whereis(erlang).
Bạn sẽ nhận được kết quả sau:
Đầu ra
{ok,"Tutorialspoint"}
Lập trình đồng thời trong Erlang cần phải có các nguyên tắc hoặc quy trình cơ bản sau.
Danh sách bao gồm các nguyên tắc sau:
piD = đẻ trứng (Vui vẻ)
Tạo một quy trình đồng thời mới để đánh giá Vui vẻ. Tiến trình mới chạy song song với trình gọi. Một ví dụ như sau:
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
spawn(fun() -> server("Hello") end).
server(Message) ->
io:fwrite("~p",[Message]).
Đầu ra của chương trình trên là:
Đầu ra
“Hello”
Pid! Thông điệp
Gửi thông báo tới quy trình với số nhận dạng Pid. Gửi tin nhắn không đồng bộ. Người gửi không chờ đợi mà tiếp tục với những gì họ đã làm.‘!’ được gọi là toán tử gửi.
Một ví dụ như sau:
Thí dụ
-module(helloworld).
-export([start/0]).
start() ->
Pid = spawn(fun() -> server("Hello") end),
Pid ! {hello}.
server(Message) ->
io:fwrite("~p",[Message]).
Nhận… kết thúc
Nhận một tin nhắn đã được gửi đến một quá trình. Nó có cú pháp sau:
Cú pháp
receive
Pattern1 [when Guard1] ->
Expressions1;
Pattern2 [when Guard2] ->
Expressions2;
...
End
Khi một thông báo đến trong quá trình này, hệ thống sẽ cố gắng đối sánh nó với Pattern1 (có thể có Guard1); nếu điều này thành công, nó sẽ đánh giá Biểu thức1. Nếu mẫu đầu tiên không khớp, nó sẽ thử Mẫu 2, v.v. Nếu không có mẫu nào khớp, thông báo sẽ được lưu để xử lý sau và quá trình chờ thông báo tiếp theo.
Ví dụ về toàn bộ quá trình với cả 3 lệnh được hiển thị trong chương trình sau.
Thí dụ
-module(helloworld).
-export([loop/0,start/0]).
loop() ->
receive
{rectangle, Width, Ht} ->
io:fwrite("Area of rectangle is ~p~n" ,[Width * Ht]),
loop();
{circle, R} ->
io:fwrite("Area of circle is ~p~n" , [3.14159 * R * R]),
loop();
Other ->
io:fwrite("Unknown"),
loop()
end.
start() ->
Pid = spawn(fun() -> loop() end),
Pid ! {rectangle, 6, 10}.
Những điều sau đây cần được lưu ý về chương trình trên:
Hàm lặp có vòng lặp kết thúc nhận. Vì vậy, khi một tin nhắn được gửi đi, nó sẽ được xử lý bởi vòng lặp kết thúc nhận.
Một tiến trình mới được tạo ra sẽ chuyển đến hàm vòng lặp.
Thông báo được gửi đến quá trình sinh sản thông qua Pid! lệnh tin nhắn.
Đầu ra của chương trình trên là:
Đầu ra
Area of the Rectangle is 60
Số lượng quy trình tối đa
Trong đồng thời, điều quan trọng là phải xác định số lượng quá trình tối đa được phép trên một hệ thống. Sau đó, bạn sẽ có thể hiểu có bao nhiêu tiến trình có thể thực thi đồng thời trên một hệ thống.
Hãy xem một ví dụ về cách chúng ta có thể xác định số lượng quá trình tối đa có thể thực thi trên một hệ thống là gì.
-module(helloworld).
-export([max/1,start/0]).
max(N) ->
Max = erlang:system_info(process_limit),
io:format("Maximum allowed processes:~p~n" ,[Max]),
statistics(runtime),
statistics(wall_clock),
L = for(1, N, fun() -> spawn(fun() -> wait() end) end),
{_, Time1} = statistics(runtime),
{_, Time2} = statistics(wall_clock), lists:foreach(fun(Pid) -> Pid ! die end, L),
U1 = Time1 * 1000 / N,
U2 = Time2 * 1000 / N,
io:format("Process spawn time=~p (~p) microseconds~n" , [U1, U2]).
wait() ->
receive
die -> void
end.
for(N, N, F) -> [F()];
for(I, N, F) -> [F()|for(I+1, N, F)].
start()->
max(1000),
max(100000).
Trên bất kỳ máy nào có sức mạnh xử lý tốt, cả hai chức năng tối đa trên sẽ vượt qua. Sau đây là kết quả mẫu từ chương trình trên.
Maximum allowed processes:262144
Process spawn time=47.0 (16.0) microseconds
Maximum allowed processes:262144
Process spawn time=12.81 (10.15) microseconds
Nhận với thời gian chờ
Đôi khi một câu lệnh nhận có thể chờ đợi mãi mãi cho một tin nhắn không bao giờ đến. Điều này có thể là vì một số lý do. Ví dụ: có thể có một lỗi lôgic trong chương trình của chúng tôi hoặc quá trình sẽ gửi cho chúng tôi một tin nhắn có thể đã bị lỗi trước khi nó gửi tin nhắn. Để tránh sự cố này, chúng ta có thể thêm thời gian chờ vào câu lệnh nhận. Điều này đặt thời gian tối đa mà quá trình sẽ đợi để nhận được tin nhắn.
Sau đây là cú pháp của tin nhắn nhận được với thời gian chờ được chỉ định
Cú pháp
receive
Pattern1 [when Guard1] ->
Expressions1;
Pattern2 [when Guard2] ->
Expressions2;
...
after Time ->
Expressions
end
Ví dụ đơn giản nhất là tạo một hàm sleeper như trong chương trình sau.
Thí dụ
-module(helloworld).
-export([sleep/1,start/0]).
sleep(T) ->
receive
after T ->
true
end.
start()->
sleep(1000).
Đoạn mã trên sẽ ngủ trong 1000 Ms trước khi thực sự thoát ra.
Nhận có chọn lọc
Mỗi quy trình trong Erlang có một hộp thư liên kết. Khi bạn gửi tin nhắn đến quy trình, tin nhắn sẽ được đưa vào hộp thư. Lần duy nhất hộp thư này được kiểm tra là khi chương trình của bạn đánh giá một câu lệnh nhận.
Sau đây là cú pháp chung của câu lệnh Nhận chọn lọc.
Cú pháp
receive
Pattern1 [when Guard1] ->
Expressions1;
Pattern2 [when Guard1] ->
Expressions1;
...
after
Time ->
ExpressionTimeout
end
Đây là cách hoạt động của câu lệnh nhận ở trên -
Khi chúng tôi nhập một câu lệnh nhận, chúng tôi bắt đầu một bộ đếm thời gian (nhưng chỉ khi phần sau có trong biểu thức).
Lấy thư đầu tiên trong hộp thư và thử đối sánh nó với Pattern1, Pattern2, v.v. Nếu đối sánh thành công, thư sẽ bị xóa khỏi hộp thư và các biểu thức sau mẫu được đánh giá.
Nếu không có mẫu nào trong câu lệnh nhận khớp với thư đầu tiên trong hộp thư, thì thư đầu tiên sẽ bị xóa khỏi hộp thư và đưa vào “hàng đợi lưu”. Thư thứ hai trong hộp thư sau đó được thử. Quy trình này được lặp lại cho đến khi tìm thấy một thư phù hợp hoặc cho đến khi tất cả các thư trong hộp thư đã được kiểm tra.
Nếu không có thư nào trong hộp thư trùng khớp, thì quá trình sẽ bị tạm ngừng và sẽ được lên lịch lại để thực hiện vào lần tiếp theo một thư mới được đưa vào hộp thư. Lưu ý rằng khi có thư mới, các thư trong hàng đợi lưu sẽ không được gửi lại; chỉ có tin nhắn mới được khớp.
Ngay sau khi một thư đã được đối sánh, thì tất cả các thư đã được đưa vào hàng đợi lưu sẽ được chuyển lại vào hộp thư theo thứ tự mà chúng đến trong quá trình. Nếu bộ hẹn giờ đã được đặt, nó sẽ bị xóa.
Nếu bộ đếm thời gian trôi qua khi chúng ta đang đợi một tin nhắn, thì hãy đánh giá biểu thức ExpressionsTimeout và đặt mọi tin nhắn đã lưu trở lại hộp thư theo thứ tự mà chúng đến trong quá trình.
Khi nói về hiệu suất, những điểm sau đây cần được lưu ý về Erlang.
Funs are very fast - Funs được cung cấp kiểu dữ liệu riêng trong R6B và được tối ưu hóa hơn nữa trong R7B.
Using the ++ operator- Toán tử này cần được sử dụng theo cách thích hợp. Ví dụ sau đây là cách sai để thực hiện một phép toán ++.
Thí dụ
-module(helloworld).
-export([start/0]).
start()->
fun_reverse([H|T]) ->
fun_reverse(T)++[H];
fun_reverse([]) ->
[].
Khi toán tử ++ sao chép toán hạng bên trái của nó, kết quả được sao chép nhiều lần, dẫn đến độ phức tạp bậc hai.
Using Strings- Xử lý chuỗi có thể chậm nếu thực hiện không đúng cách. Trong Erlang, bạn cần suy nghĩ thêm một chút về cách sử dụng các chuỗi và chọn một cách biểu diễn thích hợp. Nếu bạn sử dụng biểu thức chính quy, hãy sử dụng mô-đun lại trong STDLIB thay vìobsolete regexp module.
BEAM is a Stack-Based Byte-Code Virtual Machine- BEAM là một máy ảo dựa trên thanh ghi. Nó có 1024 thanh ghi ảo được sử dụng để giữ các giá trị tạm thời và để truyền các đối số khi gọi các hàm. Các biến cần tồn tại một lệnh gọi hàm được lưu vào ngăn xếp. BEAM là một trình thông dịch mã luồng. Mỗi lệnh là từ trỏ trực tiếp đến mã C thực thi, làm cho việc gửi lệnh rất nhanh.
Đôi khi chúng tôi muốn chạy một chương trình tiếng nước ngoài bên trong Hệ thống thời gian chạy Erlang. Trong trường hợp này, chương trình được viết dưới dạng thư viện chia sẻ được liên kết động vào hệ thống thời gian chạy Erlang. Trình điều khiển được liên kết xuất hiện với lập trình viên dưới dạng chương trình cổng và tuân theo chính xác giao thức giống như đối với chương trình cổng.
Tạo trình điều khiển
Tạo trình điều khiển được liên kết trong là cách hiệu quả nhất để giao tiếp mã ngoại ngữ với Erlang, nhưng nó cũng nguy hiểm nhất. Bất kỳ lỗi nghiêm trọng nào trong trình điều khiển được liên kết sẽ làm hỏng Hệ thống Erlang.
Sau đây là một ví dụ về triển khai trình điều khiển trong Erlang:
Thí dụ
-module(helloworld).
-export([start/0, stop/0]).
-export([twice/1, sum/2]).
start() ->
start("example1_drv" ).
start(SharedLib) ->
case erl_ddll:load_driver("." , SharedLib) of
ok -> ok;
{error, already_loaded} -> ok;
_ -> exit({error, could_not_load_driver})
end,
spawn(fun() -> init(SharedLib) end).
init(SharedLib) ->
register(example1_lid, self()),
Port = open_port({spawn, SharedLib}, []),
loop(Port).
stop() ->
example1_lid ! stop.
twice(X) -> call_port({twice, X}).
sum(X,Y) -> call_port({sum, X, Y}). call_port(Msg) ->
example1_lid ! {call, self(), Msg}, receive
{example1_lid, Result} ->
Result
end.
LINKED-IN DRIVERS 223
loop(Port) ->
receive
{call, Caller, Msg} ->
Port ! {self(), {command, encode(Msg)}}, receive
{Port, {data, Data}} ->
Caller ! {example1_lid, decode(Data)}
end,
loop(Port);
stop -> Port !
{self(), close},
receive
{Port, closed} ->
exit(normal)
end;
{'EXIT', Port, Reason} ->
io:format("~p ~n" , [Reason]),
exit(port_terminated)
end.
encode({twice, X}) -> [1, X];
encode({sum, X, Y}) -> [2, X, Y]. decode([Int]) -> Int.
Xin lưu ý rằng làm việc với trình điều khiển là vô cùng phức tạp và cần cẩn thận khi làm việc với trình điều khiển.
Ở Erlang, inets librarycó sẵn để xây dựng máy chủ web ở Erlang. Chúng ta hãy xem xét một số chức năng có sẵn trong Erlang để lập trình web. Người ta có thể triển khai máy chủ HTTP, còn được gọi là httpd để xử lý các yêu cầu HTTP.
Máy chủ triển khai nhiều tính năng, chẳng hạn như -
- Lớp cổng bảo mật (SSL)
- Giao diện kịch bản Erlang (ESI)
- Giao diện cổng chung (CGI)
- Xác thực người dùng (sử dụng Mnesia, Dets hoặc cơ sở dữ liệu văn bản thuần túy)
- Định dạng tệp nhật ký chung (có hoặc không hỗ trợ disk_log (3))
- Bí danh URL
- Bản đồ hành động
- Danh sách thư mục
Công việc đầu tiên là khởi động thư viện web thông qua lệnh.
inets:start()
Bước tiếp theo là thực hiện chức năng bắt đầu của thư viện inets để máy chủ web có thể được triển khai.
Sau đây là một ví dụ về việc tạo một quy trình máy chủ web trong Erlang.
Ví dụ
-module(helloworld).
-export([start/0]).
start() ->
inets:start(),
Pid = inets:start(httpd, [{port, 8081}, {server_name,"httpd_test"},
{server_root,"D://tmp"},{document_root,"D://tmp/htdocs"},
{bind_address, "localhost"}]), io:fwrite("~p",[Pid]).
Những điểm sau đây cần lưu ý về chương trình trên.
Số cổng phải là duy nhất và không được sử dụng bởi bất kỳ chương trình nào khác. Cáchttpd service sẽ được bắt đầu trên cổng này không.
Các server_root và document_root là các tham số bắt buộc.
Đầu ra
Sau đây là kết quả của chương trình trên.
{ok,<0.42.0>}
Để thực hiện một Hello world web server trong Erlang, hãy thực hiện các bước sau:
Step 1 - Thực hiện đoạn mã sau -
-module(helloworld).
-export([start/0,service/3]).
start() ->
inets:start(httpd, [
{modules, [
mod_alias,
mod_auth,
mod_esi,
mod_actions,
mod_cgi,
mod_dir,
mod_get,
mod_head,
mod_log,
mod_disk_log
]},
{port,8081},
{server_name,"helloworld"},
{server_root,"D://tmp"},
{document_root,"D://tmp/htdocs"},
{erl_script_alias, {"/erl", [helloworld]}},
{error_log, "error.log"},
{security_log, "security.log"},
{transfer_log, "transfer.log"},
{mime_types,[
{"html","text/html"}, {"css","text/css"}, {"js","application/x-javascript"} ]}
]).
service(SessionID, _Env, _Input) -> mod_esi:deliver(SessionID, [
"Content-Type: text/html\r\n\r\n", "<html><body>Hello, World!</body></html>" ]).
Step 2- Chạy đoạn mã như sau. Biên dịch tệp ở trên và sau đó chạy các lệnh sau trongerl.
c(helloworld).
Bạn sẽ nhận được kết quả sau.
{ok,helloworld}
Lệnh tiếp theo là -
inets:start().
Bạn sẽ nhận được kết quả sau.
ok
Lệnh tiếp theo là -
helloworld:start().
Bạn sẽ nhận được kết quả sau.
{ok,<0.50.0>}
Step 3 - Bây giờ bạn có thể truy cập url - http://localhost:8081/erl/hello_world:service.