В чем разница между 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 ответов
несколько различий, которые я могу придумать:
- при использовании
defdelegate
ваше намерение очень ясно, вы просто делегируете метод другому методу в другом модуле. И что это просто тупой экспедитора. - С
defdelegate
вы не можете изменитьarguments
, будь то порядок, добавление или удаление аргументов. Итак, если все, что вы действительно хотите, это переслать вызов метода usedefdelgate
как есть меньше возможностей, чтобы испортить. - в некоторых случаях
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