+8

Tìm hiểu ngôn ngữ Elixir

Giới thiệu

Elixir là ngôn ngữ hướng chức năng được phát triển trên nền tảng Erlang. Chính vì chạy trên Erlang Virtual Machine nên Elixir có hiệu suất cực kì cao. Các ứng dụng được phát triển bằng Elixir có thể chạy hàng trăm nghìn process chỉ trên cùng một server, tận dụng tối đa ưu thế của phần cứng máy tính. Tuy nhiên Elixir lại có cú pháp dể đọc và dể hiểu hơn nhiều so với Erlang. Nhiều người cho rằng, Elixir là "Ruby for Erlang". Cộng đồng Ruby trên thế giới đang chuyển dần sự chú ý sang ngôn ngữ này. Vậy nó có gì hot? Chúng ta cùng tìm hiểu nào!

Cách cài đặt

OSX

Việc cài đặt rất đơn giản khi sử dụng Homebrew:

~ brew update
~ brew install erlang
~ brew install elixir

Khi cài đặt thành công, bạn có thể chạy dòng lệnh dưới để kiểm tra:

~ elixir -v
> Elixir 1.0.2

Ubuntu

  1. Thêm Erlang Solutions repo:
wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && sudo dpkg -i erlang-solutions_1.0_all.deb
  1. Chạy:
sudo apt-get update
  1. Cài Erlang và các platforms cần thiết:
sudo apt-get install esl-erlang
  1. Cài Elixir:
sudo apt-get install elixir

Với các hệ điều hành khác

Bạn có thể tham khảo thêm tại đây.

Cơ bản về Elixir

Tương tự như irb của Ruby, Elixir cung cấp cho chúng ta 1 bộ REPL iex

> iex

Biến:

iex(1)> name = "rbin"
#=> "rbin"

Atoms

Trong Elixir, mỗi Atom là một hằng số mà tên cũng chính là giá trị của nó.

iex(2)> :this_is_an_atom
#=> :this_is_an_atom
iex(3)> :my_atom == :atom
#=> false

Tuples:

Chúng ta dùng cặp ngoặc nhọn để định nghĩa Tuples. Trong Elixir, Tuples được lưu trực tiếp trong bộ nhớ, chính vậy, khi lấy size của Tuple hay truy cập các phần tử của nó cực nhanh, tuy nhiên việc cập nhật hay thêm phần tử yêu cầu phải copy toàn bộ tuple trong bộ nhớ.

iex(4)> tuple = {:hello, "world"}
#=> {:hello, "world"}
iex(5)> elem(tuple, 1)
#=> "world"

Lists:

List cũng đc lưu trong bộ nhớ, có thể chèn hoặc nối thêm các phần tử:

iex(8)> list = [1, 2, :atom]
#=> [1, 2, :atom]
iex(9)> ["string"] ++ list
#=> ["string", 1, 2, :atom]
iex(10)> list ++ [31]
#=> [1, 2, :atom, 31]

Có nhiều hàm rất hữu dụng khi làm việc với list, bao gồm cả việc lấy "Head & Tail":

iex(11)> hd(list)
#=> 1
iex(12)> tl(list)
#=> [2, :atom]

Anonymous Functions

Trong Elixir, ta có thể truyền funtions như các đối số đến các fuctions khác. Ở bên dưới, chúng ta định nghĩa 1 biến add chứa 1 function, sau đó truyền nó như 1 đối số đến is_function.

iex(14)> add = fn a, b -> a + b end
#Function<12.90072148/2 in :erl_eval.expr/5>

iex(15)> add.(13, 31)
#=> 44

iex(16)> is_function(add)
#=> true

Tổ chức projects với Mix

Mix là một công cụ siêu hữu dụng cho phép chúng ta dễ dàng tạo ra, tổ chức, biên dịch và test project. Để khởi tạo 1 project mới với Mix, chỉ cần chạy lệnh đơn giản:

mix new myapp --module MyApp

Lệnh này sẽ khởi tạo 1 thư mục mới tên myapp với vài files bên trong. Đồng thời cũng định nghĩa 1 module MyApp trong lib/myapp.ex.

* creating README.md
* creating .gitignore
* creating mix.exs
* creating config
* creating config/config.exs
* creating lib
* creating lib/myapp.ex
* creating test
* creating test/test_helper.exs
* creating test/myapp_test.exs

Your mix project was created successfully.
You can use mix to compile it, test it, and more:
cd myapp
mix test

Chúng ta đã có các file cần thiết cho cấu trúc 1 dự án cơ bản. File mix.exs là file chứa các config chính của dự án, và quản lý các gói phụ thuộc. Chúng ta có test/folder, có thể viết test như Ruby 😄, chúng ta cũng có lib/folder chứa source files của dự án. Nếu chạy mix test, ta được kết quả như bên dưới:

$ mix test
Compiled lib/myapp.ex
Generated myapp.app
.
Finished in 0.04 seconds (0.04s on load, 0.00s on tests)
1 tests, 0 failures
Randomized with seed 543313

Concurrency

Cũng giống như Erlang, Elixir sử dụng 'Actor' model cho việc truy cập đồng thời(xử lý nhiều task cùng lúc). Toàn bộ code chạy trong các Process, và những processes này độc lập với nhau. Mỗi process sẽ được indentify thông qua PID

iex(1)> spawn(fn -> IO.puts 1 + 1 end)
#=> 2
#PID<0.55.0>

Các process sẽ giao tiếp với nhau thông qua sendingreceiving message

iex> send self(), {:hello, "world"}
{:hello, "world"}
iex> receive do
...>   {:hello, msg} -> msg
...>   {:world, msg} -> "won't match"
...> end
"world"

Việc return lại PID rất hữu dụng, ta có thể gán nó vào biến và sử dụng nó để gửi tin đến các process. Trước khi làm điều đó, ta cần tạo 1 receive để nhận tin nhắn chúng ta gửi.

defmodule Geometry do
  def area_loop do
    receive do
      {:rectangle, w, h} ->
        IO.puts("Area = #{w * h}")
        area_loop()
      {:circle, r} ->
        IO.puts("Area = #{3.14 * r * r}")
        area_loop()
    end
  end
end

Sau đó, tạo 1 process, gán nó cho pid

pid = spawn(fn -> Geometry.area_loop() end)
#=> #PID<0.40.0>

Ta có thể gửi messages đến pid trên, kết quả nhận đc tùy thuộc vào atom gửi kèm:

send pid, {:rectangle, 2, 3}
#=> Area = 6
# {:rectangle,2,3}

send pid, {:circle, 2}
#=> Area = 12.56000000000000049738
# {:circle,2}

Ngoài ra, ta có thể kiểm tra xem process nào đang chạy bằng cách sử dụng function Process.alive?.

Process.alive?(pid)
#=> false

Kết luận

Elixir có rất nhiều tính năng tuyệt vời, những điều liệt kê ở bên trên chỉ là thứ cơ bản ban đầu. Bạn đọc nếu có hứng thú có thể tìm hiểu sâu hơn về ngôn ngữ này. Dưới đây là những điểm hay ho của Elixir:

  • Là một ngôn ngữ dễ học, cú pháp tương tự Ruby, và cũng tựa tựa như Erlang.
  • Cộng đồng hỗ trợ lớn
  • Mô hình chạy đa tác vụ mạnh mẽ
  • Mix ngon ko thể ngon hơn
  • Tài liệu đầy đủ chả thiếu thứ gì
  • Tương lai rộng mở

Tham khảo


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.