使用方括号调用模块或模块功能

时间:2018-07-10 22:48:34

标签: elixir

在Ruby中,如果您这样定义,则可以使用[]来调用类或模块:

class Pair
  def self.[](pair_name)
    ...return pair by name
  end
end

Elixir中是否有任何等效项允许您通过方括号(卷曲/圆括号)调用模块函数?

我想为方法提供一个简短的别名,以避免这样的调用: Pair.from_name(pair_name),然后执行类似Pair.[pair_name]的操作。

4 个答案:

答案 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}