Clojure 如何以及为什么使用defmulti和defmethod?有什么好处?

Clojure 如何以及为什么使用defmulti和defmethod?有什么好处?,clojure,Clojure,我想知道为什么使用defmulti和defmethod? 有什么好处? 你如何使用它?请解释代码中发生了什么。在“一般术语”中,你可以称之为“如果/否则”,在“打动我”中,你可以用“动态调度”、“运行时多态性”等来命名 假设您想要定义一个函数“Add”,它应该适用于各种数据类型,比如Int,它应该添加数字,如果是字符串,它应该连接字符串。现在使用if-else实现它非常简单,基本上你检查参数的类型,如果它们是整数,然后添加它们,如果它们是字符串,那么concat-else抛出异常。但问题是,如果

我想知道为什么使用defmulti和defmethod? 有什么好处? 你如何使用它?请解释代码中发生了什么。

在“一般术语”中,你可以称之为“如果/否则”,在“打动我”中,你可以用“动态调度”、“运行时多态性”等来命名

假设您想要定义一个函数“Add”,它应该适用于各种数据类型,比如Int,它应该添加数字,如果是字符串,它应该连接字符串。现在使用if-else实现它非常简单,基本上你检查参数的类型,如果它们是整数,然后添加它们,如果它们是字符串,那么concat-else抛出异常。但问题是,如果您想在add函数中添加对新数据类型的支持,您需要修改add函数,这在您不控制add源的情况下可能无法实现,例如在某些库中定义了add。
defmulti
defmethod
允许您解决此问题,即在不修改其代码的情况下向现有函数添加新案例

(defmulti-add(fn[ab][(a型)(b型)])

add是函数名,匿名函数是if/else,基本上这将在add参数上调用,如果有任何实现,将检查此函数的返回值。现在让我们为Integer实现它

(defmethod add[Integer-Integer]([ab](+ab)))

[Integer Integer]
是我们在
defmulti
中定义的匿名函数的返回值上的排序开关大小写,然后是实现

类似地,我们也可以对字符串进行处理

(defmethod添加[String字符串]([ab](strab)))

用整数调用它
(添加(int 1)(int 2))

用字符串调用它
(添加“hello”“world”)


使用与我们的if/else不匹配的内容调用它,即尚未对案例实施,将导致阅读答案(并使用上面提供的示例)后观察到的异常情况,以下内容也有助于理解:

执行命令时:

(add (int 5) (int 2))
所发生的情况是执行“add defmulti”,从而生成一个列表:

[Integer Integer]
生成后,它将查找上面列表中标识的任何“添加定义方法”,即:

(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)


Multimethods有助于根据传递的参数调用方法。它可以根据参数类型/或参数的某些属性调用相应的方法。 示例1基于类型

test=> (defmulti multiply (fn [a b] [(type a) (type b)]))
#'test/multiply
test=> (defmethod multiply [Integer Integer] [a b] (* a b))
#object[clojure.lang.MultiFn 0x189f7b45 "clojure.lang.MultiFn@189f7b45"]
test=> (defmethod multiply [String String] [a b] (str a b))
#object[clojure.lang.MultiFn 0x189f7b45 "clojure.lang.MultiFn@189f7b45"]
test=> (multiply 10 10)
test=> (multiply (int 10) (int 10))
100
test=> (multiply "10" "10")
"1010"
示例2基于属性

test=> (defmulti mn (fn[a b] ( < a b ) ))
#'test/mn
test=> (defmethod mn true [a b] (+ a b) )
#object[clojure.lang.MultiFn 0x700f6a44 "clojure.lang.MultiFn@700f6a44"]
test=> (defmethod mn false [a b] (- a b) )
#object[clojure.lang.MultiFn 0x700f6a44 "clojure.lang.MultiFn@700f6a44"]
test=> (mn 1 2)
3
test=> (mn 2 1)
1
test=> (mn 1 1)
0
test=>(defmulti-mn(fn[ab]((定义方法mn真[AB](+AB))
#对象[clojure.lang.MultiFn 0x700f6a44”clojure.lang。MultiFn@700f6a44"]
测试=>(定义方法mn false[AB](-AB))
#对象[clojure.lang.MultiFn 0x700f6a44”clojure.lang。MultiFn@700f6a44"]
测试=>(mn 1 2)
3.
测试=>(mn 2 1)
1.
测试=>(mn 1)
0

您能定义什么是多重方法吗?如果不是的话,我很乐意向你解释我曾经问过一个问题:我也回答了我自己的问题,这可能会帮助你理解什么是多重方法非常感谢你!这很有帮助!谢谢你的解释!
test=> (defmulti mn (fn[a b] ( < a b ) ))
#'test/mn
test=> (defmethod mn true [a b] (+ a b) )
#object[clojure.lang.MultiFn 0x700f6a44 "clojure.lang.MultiFn@700f6a44"]
test=> (defmethod mn false [a b] (- a b) )
#object[clojure.lang.MultiFn 0x700f6a44 "clojure.lang.MultiFn@700f6a44"]
test=> (mn 1 2)
3
test=> (mn 2 1)
1
test=> (mn 1 1)
0