【问题标题】:Elixir without prefixing functions with module?没有模块前缀功能的Elixir?
【发布时间】:2015-11-06 23:35:07
【问题描述】:

我查看了一些 Elixir 项目,看到了这样的代码:

value = Dict.get(options, :key)

有没有办法让它更短并利用 调度/协议?似乎有一些陈述,如 importuserequire 在 Elixir 中。

所以看起来应该可以编写短代码并让 编译器确定它应该使用 Dict.get 还是 String.get:

import Dict, String

# Getting :key from the Dict.
value = get options, :key

# Getting the second char from the String
char = get "some-string", 2

这种方法在 Elixir 中有效吗? IE。是否可以写短 和紧凑的代码,而不是像长的完全前缀的名称 A.B.C.do_something?

【问题讨论】:

  • 你想要的是类型推断。即使在支持该类型的语言(主要是 ML 家族语言)中,有时也需要类型注释。我的意思是,即使在类型推断语言中,您有时也可能不得不做一些类似于 Dict.get 或 String.get 的事情。此外,虽然更短的代码是一个好目标,但其他开发人员能够阅读您的代码也是一个重要目标。从这个角度来看,强制消歧并不完全是一件坏事。
  • 这并不总是一个好主意,它会使您的代码更短,但是当您在 6 个月后返回它时,它会变得更加难以弄清楚,因为您遇到了 where 的情况这 ????是否定义了该函数

标签: elixir


【解决方案1】:

您绝对可以使用别名编写简短、紧凑的代码。只要确保你不混淆自己。检查offical documentation

iex(1)> alias Enum, as: E
nil
iex(2)> E.reduce [1,2,3,4], &(&1+&2)
10

至于你问题的第一部分。导入模块时,冲突会显示模棱两可的错误。例如

iex(1)> import Map, only: [delete: 2]
iex(5)> delete %{a: 4,b: 5}, :a
iex(6)> import List, only: [delete: 2]
iex(8)> delete %{a: 4,b: 5}, :a       
** (CompileError) iex:8: function delete/2 imported from both List and Map, call is ambiguous
    (elixir) src/elixir_dispatch.erl:111: :elixir_dispatch.expand_import/6
    (elixir) src/elixir_dispatch.erl:82: :elixir_dispatch.dispatch_import/5

因此,请确保只从模块中导入有用的函数。使用 only 关键字。另一个不错的选择是利用import 中的词法作用域。您可以在哪里指定要在哪里使用导入,并且只有该部分会受到影响。这是一个例子

defmodule Math do
  def some_function do
    import List, only: [duplicate: 2]
    duplicate(:ok, 10)
  end

  def other_function do
    duplicate(:ok, 10)#this will show error since import is only present inside some_function
  end
end

或者protocol 可能是您正在寻找的东西。文档会告诉您您需要了解的内容,我会在此处提供一个简短的摘要。

defprotocol Get do
  @doc "Returns the data,for given key"
  def get(data,key)
end

然后你可以为你需要的任何类型实现它

defimpl Get, for: Map do
  def get(data,key), do: Map.get(data,key)
end

defimpl Get, for: Keyword do
  def get(data,key), do: Keyword.get(data,key)
end

defimpl Blank, for: Any do
  def blank?(data,key), do: raise(ArgumentError, message: "Give proper type for key")
end

【讨论】:

  • 伤心,我担心它会这样工作。 alias 不能解决问题,我想使用多态性(或在 FP 中调用的方法调度/协议)。重要的是,我不想记住应该从 Enum(或 E)还是从 Dict(或 D)获取“get”方法。
  • 我有点确定这在 Elixir 中是不可能的,因为它是一种动态类型语言,所以 Elixir 中的所有类型都是在运行时推断出来的。但是有一些叫做协议的东西,它可以为你工作。 elixir-lang.org/getting-started/protocols.html
  • 谢谢,我去看看。尽管人们不使用协议似乎很奇怪...,但我检查了几个存储库,似乎它们都在使用A.B.C.some_function 表达式。
  • A.B.C.some_function 是模块的嵌套。 elixir-lang.org/getting-started/…
【解决方案2】:

您还可以结合使用 import :only 和 import :except 来获得您正在寻找的行为。查看here 了解更多详情。


编辑:

我想到了另一种可能的方法。您还可以通过匿名函数创建一个较短的名称。像这样的:

dget = &(Dict.get/2)

sget = &(String.get/2)

那么您的示例代码将如下所示:

value = dget.(options, :key)

char = sget.("some-string", 2)

虽然这当然会起作用,但我认为它可能仍然不是您想要的。我将此添加到我的答案中,仅供可能遇到此问答的其他人使用,以帮助就可能的替代方案提供更完整的答案。

【讨论】:

    猜你喜欢
    • 2015-04-24
    • 2019-09-04
    • 1970-01-01
    • 2017-09-14
    • 1970-01-01
    • 1970-01-01
    • 2016-04-14
    • 1970-01-01
    • 2019-11-24
    相关资源
    最近更新 更多