Я хотел бы знать, почему используются defmulti и defmethod? Каковы преимущества? И как вы его используете? Пожалуйста, объясните, что происходит в коде.
Как и почему используется defmulti и defmethod? и каковы преимущества?
Ответ 1
В "общих терминах" вы бы назвали это if/else на стероидах и в стиле "произвести впечатление", который вы назвали бы им с "динамической отправкой", "полином времени выполнения" и т.д.
Предположим, вы хотите определить функцию "Добавить", которая должна работать для разных типов данных, например, в случае Int, она должна добавить числа, в случае строк она должна конкатцировать строки. Теперь его очень просто реализовать, используя if else, в основном вы проверяете тип аргументов и, если они являются целыми числами, затем добавляйте их, если они являются строками, тогда concat их еще генерирует исключение. Но проблема заключается в том, что если вы хотите добавить поддержку нового типа данных в свою функцию добавления, вам нужно будет изменить функцию добавления, что может быть невозможно в тех случаях, когда вы не выполняете контролировать источник добавления, например, в случае, если он определен в некоторой библиотеке и т.д.
defmulti
и defmethod
позволяет решить эту проблему, добавив новый случай к существующей функции без изменения ее кода.
(defmulti add (fn [a b] [(type a) (type b)]))
add - это имя функции, анонимная функция - это ваш if/else, в основном это будет вызываться в ваших аргументах добавления, и возвращаемое значение этой функции будет проверяться, если есть какая-либо реализация. Теперь давайте реализуем его для Integer.
(defmethod add [Integer Integer] ([a b] (+ a b)))
[Integer Integer]
- это регистр сортировки по возвращаемому значению анонимной функции, определенной в defmulti
, а затем реализации.
Аналогично мы можем сделать для строк
(defmethod add [String String] ([a b] (str a b)))
Вызов его целыми числами
(add (int 1) (int 2))
Вызов со строками
(add "hello" "world")
Вызов его с чем-то, что не соответствует нашему if/else. i.e еще не реализация для случая приведет к исключению
Ответ 2
Из того, что я наблюдал после прочтения ответа (и используя приведенный выше пример), также полезно понять следующее:
при выполнении команды:
(add (int 5) (int 2))
Что происходит, так это то, что выполняется 'add defmulti', создавая список:
[Integer Integer]
с созданным, он ищет какой-либо "add defmethod", который идентифицируется с помощью вышеперечисленного списка i.e.:
(add [Integer Integer])
И передает аргументы, которые он получил.
Другой способ определения нескольких методов, чтобы упростить передачу аргументов:
(defmulti add (fn [a b] [(type a) (type b)]))
(defmethod add [Integer Integer] [a b] (+ a b))
(defmethod add [String String] [a b] (str a b))
Затем запустите функцию как:
(add 12 73)
или
(add "thank" "you")