在Ruby中,如果您这样定义,则可以使用[]
来调用类或模块:
class Pair
def self.[](pair_name)
...return pair by name
end
end
Elixir中是否有任何等效项允许您通过方括号(卷曲/圆括号)调用模块函数?
我想为方法提供一个简短的别名,以避免这样的调用:
Pair.from_name(pair_name)
,然后执行类似Pair.[pair_name]
的操作。
答案 0 :(得分:2)
elixir AFAIK当前没有此类功能。
但是,如果您想使用较短的函数名,为什么不使用模式匹配,保护符和import
:
defmodule Pair do
defstruct name: "Default"
def pair(name) when is_bitstring(name), do: %Pair{name: name}
def pair(id) when is_integer(id), do: %Pair{name: "#{id}"}
end
iex(1)> import Pair, only: [pair: 1]
Pair
iex(2)> pair("what")
%Pair{name: "what"}
iex(3)> pair(3)
%Pair{name: "3"}
答案 1 :(得分:2)
好吧,我希望被证明是错误的,但是我必须得出结论,这是不可能的。我搞砸了一些事情,似乎不可能。
来自the documentation of Access
:
请注意,动态查找语法(
term[key]
)大致 转换为Access.get(term, key, nil)
。
因此,如果我们要使方括号语法起作用,就需要以某种方式插入Access.get
中。看一下source code for Access.get
,我们发现它具有
def get(container, key, default \\ nil) def get(%module{} = container, key, default) # (1) def get(map, key, default) when is_map(map) # (2) def get(list, key, default) when is_list(list) and is_atom(key) # (3) def get(list, key, _default) when is_list(list) # (4) def get(nil, _key, default) # (5)
让我们分解这些。最上面的只是原型,所以它告诉我们的并不多。 (2),(3)和(4)仅适用于列表和地图,而(5)是使nil更方便的一种保护措施。 (1)是唯一可以与我们合作的人;如果container
是结构类型(例如来自模块),那么我们可以通过在自己的模块中采用Access
行为来陷入这种行为。但是,这是我们碰到砖墙的地方。如果我们进入解释器并确切地询问它 模块的名称,就会遇到问题。
iex(1)> defmodule Foo do end
{:module, Foo, ...}
iex(2)> i Foo
Term
Foo
Data type
Atom
...
因此,模块的名称只是一个原子。在Ruby中,类是Class
类的实例,因此可以相当自由地对其进行修改。但是,在Elixir中,Foo
只是一个原子(在Ruby的术语中是一个符号),Access.get
的情况都不是将原子作为第一个参数的。
我很乐意被证明是错误的,但是据我所知,我可以肯定地说这是不可能的。
答案 2 :(得分:1)
我不能完全确定我了解您要做什么,因此此答案可能不是您想要的。
在Elixir中,[]
语法是为数据结构保留的,基本上是Access.get/2
的快捷方式。默认情况下,[]
在自定义结构上不起作用,但是有一种方法可以“教” Access
如何处理自己的结构。为此,您需要实现Access
行为。
假设我们具有此自定义MyContainer
结构:
defmodule MyContainer do
defstruct contained: %{}
end
我们希望能够通过执行contained
来访问container[:foo]
映射中的字段。为此,我们需要实现Access
行为。
defmodule MyContainer do
defstruct contained: %{}
@behaviour Access
def fetch(%__MODULE__{contained: map}, key) do
Access.fetch(map, key)
end
def get(%__MODULE__{contained: map}, key, default) do
Access.get(map, key, default)
end
def get_and_update(%__MODULE__{contained: map}, key, update_fn) do
Access.get_and_update(map, key, update_fn)
end
def pop(%__MODULE__{contained: map}, key) do
Access.pop(map, key)
end
end
现在我们可以执行以下操作:
iex> my_map = %{foo: "bar"}
iex> my_container = %MyContainer{contained: my_map}
iex> my_container[:foo]
"bar"
答案 3 :(得分:0)
这是我在Elixir中找到的最接近的语法。
可以使用花括号定义模块方法,然后像这样使用它::atom.{}
defmodule Pair do
defstruct [:id]
def {pair_name}, do: %Pair{id: from_name(pair_name)}
def from_name(_), do: 1
end
用法:
Pair.{"some_name"} => %Pair{id: 1}