【问题标题】:Can Erlang source code be embedded in Elixir code? If so, how?Erlang 源代码可以嵌入到 Elixir 代码中吗?如果是这样,怎么做?
【发布时间】:2021-11-08 22:32:18
【问题描述】:

Elixir 源可以使用 Code.eval_string/3 注入。我没有看到文档中提到运行原始 Erlang 代码:

https://hexdocs.pm/elixir/Code.html#eval_string/3

我来自 Scala 世界,其中 Java 对象可以使用 Scala 语法调用,Scala 被编译成 Java 并通过拦截编译器输出(直接使用 scalac 生成)可见。

我感觉 Elixir 不提供这样的互操作功能,也不允许将自定义 Erlang 注入运行时。是这样吗?

【问题讨论】:

    标签: erlang elixir


    【解决方案1】:

    从 elixir 调用 erlang 代码时需要注意的另一件事。 erlang 使用字符列表作为字符串。当你调用一个接受字符串的 erlang 函数时,将字符串转换为 charlist 并将返回的字符串转换为字符串。

    例子:

    iex(17)> :string.to_upper "test"
    ** (FunctionClauseError) no function clause matching in :string.to_upper/1
    
        The following arguments were given to :string.to_upper/1:
    
            # 1
            "test"
    
        (stdlib 3.15.1) string.erl:2231: :string.to_upper/1
    iex(17)> "test" |> String.to_charlist() |> :string.to_upper
    'TEST'
    iex(18)> "test" |> String.to_charlist() |> :string.to_upper |> to_string
    "TEST"
    iex(19)>
    

    【讨论】:

    【解决方案2】:

    扩展@zwippie 所写的内容:

    所有远程函数调用(我的意思是调用具有显式设置模块/别名的函数)的形式为:

    <atom with module name>.<function name>(<arguments>)
    
    # Technically it is the same as:
    # apply(module, function_name_as_atom, [arguments])
    

    而 Elixir 中的所有“大写模块名称”都只是原子:

    is_atom(Foo) == true
    Foo == :"Elixir.Foo" # => true
    

    所以从 Elixir 的角度来看,调用 Erlang 函数和 Elixir 函数没有区别。它只是作为接收模块传递的不同原子。

    因此您可以轻松地从 Elixir 调用 Erlang 模块。这意味着您应该也可以在 Elixir 中轻松编译 Erlang AST:

    "rand:uniform(100)"
    |> :merl.quote()
    |> :erl_eval.expr(#{})
    

    不需要任何心理翻译。


    此外,您可以毫无问题地在单个 Mix 项目中混合 Erlang 和 Elixir 代码。树形结构如下:

    .
    |`- mix.exs
    |`- src
    |  `- example.erl
     `- lib
       `- example.ex
    

    example.erl 在哪里:

    -module(example).
    
    -export([hello/0]).
    
    hello() -> <<"World">>.
    

    还有example.ex:

    defmodule Example do
      def print_hello, do: IO.puts(:example.hello())
    end
    

    你可以编译项目并运行它

    mix run -e "Example.print_hello()"
    

    并且看到 Erlang 模块在同一个项目的 Elixir 代码中成功编译和执行,没有问题。

    【讨论】:

    • 非常好,非常感谢您提供的示例。
    【解决方案3】:

    您可以使用 Elixir 的 erlang 标准库模块,如 herehere 所述。

    例如:

    def random_integer(upper) do
      :rand.uniform(upper) # rand is an erlang library
    end
    

    您也可以将 erlang 包添加到您的 mix.exs 依赖项中并在您的项目中使用它们,只要这些包发布在 hex 或 github 上即可。

    您还可以在项目中同时使用 erlang 和 elixir 代码,如 here 所述。

    所以是的,完全可以从 elixir 中调用 erlang 代码。

    反之亦然,更多信息请参阅here

    Elixir 编译成 BEAM 字节码(通过 Erlang 抽象格式)。这 意味着可以从 Erlang 调用 Elixir 代码,反之亦然, 无需编写任何绑定。

    【讨论】:

    • 另外,如原始问题中所问,Code.eval_string/3: Code.eval_string(":rand.uniform(100)") #⇒ {38, []}
    • 优秀。感谢您指向我的文档。
    • 接受是因为参考了文档,但也请参阅@Hauleth 的答案,其中有很好的例子。
    猜你喜欢
    • 1970-01-01
    • 2012-10-20
    • 2012-04-08
    • 2021-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-21
    • 2020-01-21
    相关资源
    最近更新 更多