В чем разница между defdelegate и def с функцией модуля вызова непосредственно в Elixir

у меня есть модуль, который в основном используется в качестве пространства имен. Назовем это Bla. Существуют другие подмодули, которые имеют методы с конкретными функциями для этого подмодуля.

тем не менее, я хочу иметь два варианта:

1) импорт основного модуля Bla и использовать все функции из подмодулей напрямую (не писать несколько импортов отдельно)

2) импортировать только определенный подмодуль, например Bla.Subbla использовать функции только из этого модуля без импорта функции из других подмодулей

вот что у меня есть:

defmodule Bla do
  defdelegate bla_func(text), to: Bla.Subbla
  defdelegate bla_func(text, opts), to: Bla.Subbla
end

defmodule Bla do
  def bla_func(text), do: Bla.Subbla.bla_func(text)
  def bla_func(text, opts), do: Bla.Subbla.bla_func(text, opts)
end

Как правильно это сделать? У меня есть два варианта, но понятия не имею, может быть, есть гораздо лучший. Эквивалентны ли эти два варианта? И какой из них предпочтительнее? Есть ли разница в производительности?

2 ответов


несколько различий, которые я могу придумать:

  1. при использовании defdelegate ваше намерение очень ясно, вы просто делегируете метод другому методу в другом модуле. И что это просто тупой экспедитора.
  2. С defdelegate вы не можете изменить arguments, будь то порядок, добавление или удаление аргументов. Итак, если все, что вы действительно хотите, это переслать вызов метода use defdelgate как есть меньше возможностей, чтобы испортить.
  3. в некоторых случаях defdelegate не является опцией, так как вам нужно добавить больше данных в функцию пересылки, и в этом случае у вас действительно нет опции.

Итак, итог: если возможно, всегда используйте defdelegate, вы избежите нескольких классов ошибок, используя его. например, ниже:

defmodule Greet do
  def greet(name, greeting) do
    IO.puts "#{greeting} #{name}"
  end
end

defmodule DelegatedGreet do
  defdelegate greet(name, greeting), to: Greet
end

defmodule BuggyGreet do
  # scope for bugs like these
  def greet(name, greeting), do: Greet.greet(greeting, name)
end

Как сказал @JustMichael, хорошо использовать use в этом случае. Это именно то, что мне нужно.

defmodule SomeModuleWhereINeedSubbla do
  use Bla

  useful_func   # => Will print "Bla.Subbla.useful_func"
end

defmodule Bla do
  defmacro __using__(_) do
    quote do
      import Bla.Subbla
    end
  end
end

defmobule Bla.Subbla do
  def useful_func(), do: IO.puts "Bla.Subbla.useful_func"
end