Эликсир без префиксов функций с модулем?
Я посмотрел на некоторые проекты Elixir и увидел такой код:
value = Dict.get(options, :key)
Есть ли способ сделать его короче и использовать диспетчеризацию / протоколы? Кажется, что есть некоторые заявления, как import
, use
, require
в эликсире.
Таким образом, кажется, что должна быть возможность написать короткий код и позволить компилятору выяснить, использует ли он Dict.get или String.get:
import Dict, String
# Getting :key from the Dict.
value = get options, :key
# Getting the second char from the String
char = get "some-string", 2
Работает ли такой подход в Elixir? Т.е. возможно ли написать короткий и компактный код вместо длинных полностью префиксных имен, таких как A.B.C.do_something
?
2 ответа
Вы можете определенно написать короткий, компактный код, используя псевдоним. Просто убедитесь, что вы не путаете себя. Проверьте официальную документацию
iex(1)> alias Enum, as: E
nil
iex(2)> E.reduce [1,2,3,4], &(&1+&2)
10
Что касается первой части вашего вопроса. Когда вы импортируете модули, конфликты покажут неоднозначную ошибку. Например,
iex(1)> import Map, only: [delete: 2]
iex(5)> delete %{a: 4,b: 5}, :a
iex(6)> import List, only: [delete: 2]
iex(8)> delete %{a: 4,b: 5}, :a
** (CompileError) iex:8: function delete/2 imported from both List and Map, call is ambiguous
(elixir) src/elixir_dispatch.erl:111: :elixir_dispatch.expand_import/6
(elixir) src/elixir_dispatch.erl:82: :elixir_dispatch.dispatch_import/5
Поэтому убедитесь, что вы импортируете только полезные функции из модуля. only
ключевое слово. Другим хорошим вариантом будет использование лексических ограничений в импорте. Где вы можете указать, где вы хотите использовать импорт, и будет выполняться только эта часть. Вот пример
defmodule Math do
def some_function do
import List, only: [duplicate: 2]
duplicate(:ok, 10)
end
def other_function do
duplicate(:ok, 10)#this will show error since import is only present inside some_function
end
end
В качестве альтернативы протокол может быть тем, что вы ищете. Документы скажут вам, что вам нужно знать, я выложу здесь краткое резюме.
defprotocol Get do
@doc "Returns the data,for given key"
def get(data,key)
end
Затем вы можете реализовать его для любого типа, который вам требуется
defimpl Get, for: Map do
def get(data,key), do: Map.get(data,key)
end
defimpl Get, for: Keyword do
def get(data,key), do: Keyword.get(data,key)
end
defimpl Blank, for: Any do
def blank?(data,key), do: raise(ArgumentError, message: "Give proper type for key")
end
Вы также можете использовать комбинацию import:only с import: кроме как для получения искомого поведения. Проверьте здесь для более подробной информации.
РЕДАКТИРОВАТЬ:
Другой возможный подход происходит со мной. Вы также можете создать более короткое имя с помощью анонимной функции. Что-то вроде этого:
dget = &(Dict.get/2)
sget = &(String.get/2)
Тогда ваш пример кода будет выглядеть так:
value = dget.(options, :key)
char = sget.("some-string", 2)
Хотя это, конечно, сработает, я думаю, что это, вероятно, еще не то, что вы ищете. Я добавляю это к своему ответу исключительно для тех, кто может столкнуться с этими вопросами и ответами, чтобы помочь дать более полный ответ о возможных альтернативах.