1 10_000 0x53 # В шестнадесетична 0o53 # В осмична 0b11 # В двоична 3.14 # С плаваща запетая 1.0e-10
1 + 41 21 * 2 54 / 6 # Връща резултат с плаваща запетая Kernel.div(54, 6) # В повечето езици `/` прави това Kernel.rem 11, 3 # А ето как получаваме остатъка.
1 < 2 1 >= 1 1 != 2 1 == 2 1 == 1.0 # Операторът == сравнява по стойност 1 === 1.0 # Операторът === сравнява по стойност И тип 1 !== 1.0 # Операторът !== сравнява по стойност И тип
true false Kernel.is_boolean(true) is_boolean(0) true == false
true
false
:true
:false
map
keyword lists
{:ok, 2}
@
!
?
:atom :true SomeModule # Може и да не е дефиниран is_atom(:atom) is_atom(true) true == :true :"atom with a space" # Могат да се дефинират и така
Низовете в Elixir се дефинират с двойни кавички и са с UTF-8 encoding:
Elixir
"Здрасти" "Здрасти #{:Danchou}" # Интерполация
is_binary("Здрасти") String.length("Здрасти") # Брой на символи byte_size("Здрасти") # Брой на байтове "Бял" <> " мерцедес!" # Конкатенация
List
[1, 2, "три", 4.0] # Не са хомогенни length [1, 2, 3, 5, 8] # Дължината hd [1, 2, 3, 5, 8] tl [1, 2, 3, 5, 8] is_list([1, 2])
[1 | [2 | [3 | [4 | [5 | []]]]]]
[83, 79, 83] is_list('SOS')
List.to_atom([83, 79, 83]) List.to_atom([83, 79, 83, 1]) List.to_atom([83, 79, 83, 1, :s]) # List.to_integer/1 и List.to_float/1 ще опитат да върнат числа от charlist: List.to_integer('54') List.to_float('45.2') List.to_string([83, 77, 69, 82, 67, 72])
pattern matching
{:ok, 7} tuple_size({:ok, 7, 5}) is_tuple({:ok, 7, 5})
Списъци, които съдържат tuple-и от по два елемента - атом и каквато и да е стойност.
tuple
[{:one, 1}, {:two, 2}] [one: 1, two: 2]
Ако keyword list е последен аргумент на функция, можем да пропуснем квадратните скоби при извикване:
f(1, 2, three: 3, four: 4)
String.split/3
String.split("one,two,,,three,,,four", ",", trim: true)
Map
pesho = %{ name: "Пешо", age: 35, hobbies: {:drink, :smoke, :eurofootball}, job: "шлосер" } pesho[:name] pesho.name Map.fetch(pesho, :name) Map.fetch!(pesho, :name) Map.get(pesho, :name)
<< 2 >> # Цялото число 2 в 1 байт byte_size << 2 >> << 255 >> # Цялото число 255 в 1 байт << 256 >> # Превърта и става 0 <<1, 2>> # Две цели числа в два байта. byte_size << 1, 2 >>
<< 5::size(3), 1::size(1), 5::size(4) >> 0b10110101 byte_size << 5::size(3), 1::size(1), 5::size(4) >> is_bitstring << 5::size(3), 1::size(1) >> is_binary << 5::size(3), 1::size(1) >>
binary
is_binary("Стринг")
<<208, 170, 208, 156>> = "ЪМ"
fn (x) -> x + 1 end (fn (x) -> x + 1 end).(4) # Извикване is_function((fn (x) -> x + 1 end))
&(&1 + 1) (&(&1 + 1)).(4)
return
Port
Reference
PID
~r/\w+/im
(1..1000)
=
match operator
x = 5 5 = x 4 = x
Засега за match operator-а знаем:
_
{one, tWo, t3, f_our, five!} = {1, 2, 3, 4, 5} one tWo t3 f_our five!
g = fn 0 -> 0 x -> x - 1 end g.(0) g.(3)
Erlang
Ако искаме една променлива, която вече съществува да не промени стойността си при съпоставяне, можем да използваме pin оператора - ^.
pin
^
x = 5 ^x = 6
{y, ^x} = {5, 4}
Ако се опитаме да присвоим стойност на unbound променлива (досега не е съществувала), използвайки pin оператора, ще получим грешка.
unbound
^z = 4
defmodule Example do def factorial(0), do: 1 def factorial(n), do: n * factorial(n - 1) end
defmodule Questionnaire do def how_old_are_you?(age) when age > 30 do "Имаме си чичко или леличка" end def how_old_are_you?(age) when age > 20 do "Имаме си милениалче, тригърнато от живота" end def how_old_are_you?(_), do: "Дете" end Questionnaire.how_old_are_you?(21)
[a | b] = [1, 2, 3] [a | b] = [25]
[a | b] = []
defmodule ListUtils do def length([]), do: 0 def length([_head | tail]), do: 1 + length(tail) end ListUtils.length(["cat", "dog", "fish", "horse"])
defmodule Square do def of([]), do: [] def of([head | tail]), do: [head * head | of(tail)] end Square.of([1, 2, 3, 4, 5])
defmodule Fib do def bad_of(n), do: bad_fib(n, 0, 1, []) defp bad_fib(0, _current, _next, seq), do: seq defp bad_fib(n, current, next, seq) do bad_fib(n - 1, next, current + next, seq ++ [current]) end end
defmodule Fib do def of(n), do: fib(n, 0, 1, []) defp fib(0, _current, _next, seq), do: seq |> Enum.reverse() defp fib(n, current, next, seq) do fib(n - 1, next, current + next, [current | seq]) end end
defmodule ListUtils do def map([], _func), do: [] def map([head | tail], func), do: [func.(head) | map(tail, func)] end ListUtils.map([1, 2, 3, 4, 5], fn x -> x * x end)
defmodule ListUtils do def reduce([], acc, _func), do: acc def reduce([head | tail], acc, func), do: reduce(tail, func.(head, acc), func) end ListUtils.reduce(["cat", "dog", "horse"], 0, fn _head, acc -> 1 + acc end)
pesho = %{age: 35, drink: :rakia, hobbies: :just_drinking, name: "Пешо"} %{name: x} = pesho %{name: _, age: _} = pesho
defmodule A do def f(%{name: name} = person) do name end end A.f(pesho)
a = :rand.uniform(1000) if rem(a, 2) == 0 do "a's value is #{a}, it is even" else "a's value is #{a}, it is even" end
defmodule Questionnaire do def how_old_are_you?(age) do if age > 30 do "Имаме си чичко или леличка" else if age > 20 do "Имаме си милениалче, тригърнато от живота" else "Дете" end end end end
Стойността на if или на unless е стойността на израза, който се оценява.
if
unless
age = 34 name = "Слави" if age < 30 do "Младеж" end if age > 30, do: "Чичо #{name}", else: name
defmodule FizzBuzz do def of(n), do: Enum.map(1..n, &number_value/1) defp number_value(n) do cond do rem(n, 3) == 0 and rem(n, 5) == 0 -> "FizzBuzz" rem(n, 3) == 0 -> "Fizz" rem(n, 5) == 0 -> "Buzz" true -> n end end end
defmodule Questionnaire do def asl(age, sex, location) do case sex do :male -> "#{age}, М, #{location}" :female -> "#{age}, F, #{location}" _ -> "#{age}, ?, #{location}" end end end
Защо case е по-добър избор пред cond?
defmodule HR do def work_experience(years) when years > 10, do: :experienced def work_experience(years) when years > 5, do: :advanced def work_experience(_), do: :not_experienced def knows_elixir?([]), do: false def knows_elixir?([:elixir | _]), do: true def knows_elixir?([_ | rest]), do: knows_elixir?(rest) def read_cv(file_path), do: File.read(file_path) end
years = 11 languages = [:erlang, :elixir, :rust] cv_path = "/tmp/cv.txt" with :experienced <- HR.work_experience(years), true <- HR.knows_elixir?(languages), {:ok, cv} <- HR.read_cv(cv_path), do: cv
Ако някое от условията не е изпълнено, ще получим стойността му:
with :experienced <- HR.work_experience(3), true <- HR.knows_elixir?(languages), {:ok, cv} <- HR.read_cv(cv_path), do: cv
base_list = [1, 2, 3] new_list = [0 | base_list]