Elixir Language
Полиморфизм в Эликсире
Поиск…
Вступление
Полиморфизм - это предоставление единого интерфейса объектам разных типов. В принципе, он позволяет различным типам данных реагировать на одну и ту же функцию. Таким образом, одни и те же функции формируют разные типы данных для достижения такого же поведения. Язык Elixir имеет protocols
для реализации полиморфизма с чистым способом.
замечания
Если вы хотите охватить все типы данных, вы можете определить реализацию для Any
типа данных. Наконец, если у вас есть время, проверьте исходный код Enum и String.Char , которые являются хорошими примерами полиморфизма в ядре Elixir.
Полиморфизм с протоколами
Давайте реализуем базовый протокол, который преобразует температуры Кельвина и Фаренгейта в цель.
defmodule Kelvin do defstruct name: "Kelvin", symbol: "K", degree: 0 end defmodule Fahrenheit do defstruct name: "Fahrenheit", symbol: "°F", degree: 0 end defmodule Celsius do defstruct name: "Celsius", symbol: "°C", degree: 0 end defprotocol Temperature do @doc """ Convert Kelvin and Fahrenheit to Celsius degree """ def to_celsius(degree) end defimpl Temperature, for: Kelvin do @doc """ Deduct 273.15 """ def to_celsius(kelvin) do celsius_degree = kelvin.degree - 273.15 %Celsius{degree: celsius_degree} end end defimpl Temperature, for: Fahrenheit do @doc """ Deduct 32, then multiply by 5, then divide by 9 """ def to_celsius(fahrenheit) do celsius_degree = (fahrenheit.degree - 32) * 5 / 9 %Celsius{degree: celsius_degree} end end
Теперь мы внедрили наши конвертеры для типов Кельвина и Фаренгейта. Давайте сделаем некоторые преобразования:
iex> fahrenheit = %Fahrenheit{degree: 45} %Fahrenheit{degree: 45, name: "Fahrenheit", symbol: "°F"} iex> celsius = Temperature.to_celsius(fahrenheit) %Celsius{degree: 7.22, name: "Celsius", symbol: "°C"} iex> kelvin = %Kelvin{degree: 300} %Kelvin{degree: 300, name: "Kelvin", symbol: "K"} iex> celsius = Temperature.to_celsius(kelvin) %Celsius{degree: 26.85, name: "Celsius", symbol: "°C"}
Попробуем преобразовать любой другой тип данных, который не имеет реализации для функции to_celsius
:
iex> Temperature.to_celsius(%{degree: 12}) ** (Protocol.UndefinedError) protocol Temperature not implemented for %{degree: 12} iex:11: Temperature.impl_for!/1 iex:15: Temperature.to_celsius/1