在使用网络协议(http、ftp 等)这个术语后,我对它在 Elixir 中的用法感到困惑。例如,有对 Enum 模块和 Enumerable Protocol 的引用。Elixir 文档说Protocols are a mechanism to achieve polymorphism in Elixir。
它们不只是具有一组方法/功能的模块吗?有什么区别吗?
将协议视为 Java 中的接口/Python 中的抽象类(实际上,Java 接口,特别是 Python 抽象类更像是@behaviour,但无论如何。)
defprotocol Sound do
def make_sound(data)
end
defmodule Dog do
defstruct name: "Donny"
end
defimpl Sound, for: Dog do
def make_sound(data) do
"#{data.name} barks “woof”"
end
end
defmodule Cat do
defstruct name: "Hilly"
end
defimpl Sound, for: Cat do
def make_sound(data) do
"#{data.name} murrs “meow”"
end
end
Run Code Online (Sandbox Code Playgroud)
在代码中:
%Dog{} |> Sound.make_sound
#? "Donny barks “woof”"
Run Code Online (Sandbox Code Playgroud)
或者:
pet = .... # complicated code loading a struct
pet |> Sound.make_sound # here we don’t care what pet we have
Run Code Online (Sandbox Code Playgroud)
这种机制用于字符串插值:
"#{5}"
Run Code Online (Sandbox Code Playgroud)
上面的工作是因为Integer有String.Chars. 实现只是调用
WHATEVER_IN_#{} |> String.Chars.to_string
Run Code Online (Sandbox Code Playgroud)
得到一个二进制文件。例如。对于上述Dog模块,我们可能会实现String.Chars:
defimpl String.Chars, for: Dog do
def to_string(term) do
"#{term.name} barks “woof”"
end
end
Run Code Online (Sandbox Code Playgroud)
现在可以插入狗:
"#{%Dog{}}"
#? "Donny barks “woof”"
Run Code Online (Sandbox Code Playgroud)