---?color=#ffffff
---?color=#3DED20
---?color=#F62020
---?color=#ffffff
(Typespecs and Behaviours)
- Типова спецификация(type specification)
- Видове
- Синтаксис
- Дефиниране на собствени
- Поведения(Behaviours)
- dynamic dispatch
---?image=assets/thinking.png&size=auto 90%
---?image=assets/thinking.png&size=auto 90%
---?image=assets/troll.jpg&size=auto 90%
---?image=assets/answer.png&size=auto 50%
"Звучи доста спечено"
---?image=assets/troll.jpg&size=auto 90%
Elixir идва с нотация за типове.
Изглеждат така:
@type age :: pos_integer()
@type sex :: :female | :male
@type location :: String.t()
@type asl :: {age(), sex()}
Функциите са така:
defmodule Foo do
@spec is_even(integer) :: true | false
def is_even(x), do: # ... не знам как
end
Използват се главно за:
- да допринасят за документация(инструменти като ExDoc ги ползват)
- от инструменти като Dialyzer за анализ на кода за грешки
- когато пишем библиотеки за други хора
- текстовите редактори
PS1: Гледаме документацията тук
PS1: Live coding starts here
PS2: Time for behaviours
---?image=assets/dialyzer.png&size=auto 70%
---?image=assets/behaviour.jpg&size=auto 90%
---?image=assets/what.gif&size=auto 70%
Поведенията ни дават начин да правим две неща:
- даден модул имплементира разни функции
- осигурява, че са имплементирани
Ако се налага - мислите за тях като интерфейсите в !нормалните езици.
Да кажем, че бихме искали да напишем поведение за парсване на JSON/MsgPack(случайност).
Как би изглеждало това?
defmodule Parser do
@callback encode(term) :: {:ok, String.t} | {:error, String.t}
@callback decode(String.t) :: {:ok, term} | {:error, String.t}
end
И след това го вмъкваме в нашите имплементации по този начин:
defmodule JSON do
@behaviour Parser
def encode(term), do: # ... encode
def decode(str), do: # ... decode
end
defmodule MsgPack do
@behaviour Parser
def encode(term), do: # ... encode
def decode(str), do: # ... decode
end
Можем динамично да решаваме кога да извикаме даден модул.
Нищо не ни пречи да направим следното:
defmodule Parser do
# ... rest of code ...
def encode!(implementation, term) do
implementation.encode(term)
end
end
Parser.encode!(JSON, term)
# ^ - динамично
Вече можем runtime да избираме какъв формат ни трябва!
... чакай малко ...
---?image=assets/fight.jpg&size=auto 90%
Двете не правят ли близки неща?
Разликите:
- протоколите ни дават полиморфизъм над типове/дата
- поведенията ни дават динамично да се включваме където ни трябва
Един вид - протоколите са поведения + логика за dynamic dispatch
Въпроси и обратна връзка: [email protected]
---?image=assets/beers.jpg&size=auto 90%