【问题标题】:Elixir: When to use .ex and when .exs filesElixir:何时使用 .ex 以及何时使用 .exs 文件
【发布时间】:2016-07-17 11:59:30
【问题描述】:

Elixir 的文档 states

除了 Elixir 文件扩展名 .ex,Elixir 还支持 用于编写脚本的 .exs 文件。 Elixir 对这两个文件的处理方式完全相同 方式,唯一的区别是意图。 .ex 文件的目的是 在 .exs 文件用于脚本时编译,无需 编译。

但我仍然不确定何时使用哪种文件类型。 .ex 和 .exs 的缺点和用途是什么?

【问题讨论】:

    标签: elixir


    【解决方案1】:

    .ex 用于编译代码,.exs 用于解释代码。

    例如,ExUnit 测试位于 .exs 文件中,因此您不必在每次更改测试时都重新编译。如果您正在编写脚本或测试,请使用 .exs 文件。否则,只需使用 .ex 文件并编译您的代码。

    就优点/缺点而言,解释将需要更长的时间来执行(因为 elixir 必须解析、标记化等),但不需要编译即可运行。差不多就是这样 - 如果运行脚本的灵活性比优化的执行时间更重要,请使用.exs。大多数时候,你会使用.ex

    【讨论】:

      【解决方案2】:

      Elixir 将编译整个 .ex 文件。

      .exs 文件也会被编译,但在调用时会被执行。因此,.exs 文件的大多数用例是在调用时立即执行代码。考虑使用.exs 文件进行测试、迁移数据和运行脚本。将.ex 文件视为应用程序的主要业务逻辑。

      考虑这个例子

      .ex 示例

      sum.ex:

      defmodule Sum do
        def add(a, b) do
          a + b
        end
      end
      
      $ iex sum.ex
      ...
      
      Interactive Elixir (1.9.4) - press Ctrl+C to exit (type h() ENTER for help)
      iex(1)> Sum.add(1, 2)
      3
      

      .exs 示例

      sum.exs:

      defmodule Sum do
        def add(a, b)  do
          a + b
        end
      end
      
      #within same file
      
      IO.puts "The sum of 3 + 2 is: #{inspect Sum.add(3, 2)}"
      
      $ elixir sum.exs
      The sum of 3 + 2 is: 5
      

      【讨论】:

        【解决方案3】:

        我在 Elixir 版本 1.9.1 中检查它,两个扩展 .ex.exs 将使用 elixirc 编译。换句话说,我们在这两种情况下都得到了字节码(.beam 文件)。

        【讨论】:

          【解决方案4】:

          对于一些更具体的细节,以下是我注意到的关于何时使用 .ex.exs 文件的一些模式或经验法则:

          几乎所有代码都放在我的应用程序“库”目录树中的 .ex 文件中,例如在 lib 下(或者如果应用程序是旧的 Phoenix webapp,则可能是 web)。可以在应用程序的其他地方或从iex 调用代码(如果它定义了公共函数或宏)。这是默认设置。

          在选择.ex.exs 时,最重要的考虑因素可能是我想在何处(以及何时)调用该代码:

          1. 在应用程序本身中 – .ex
          2. 来自iex(例如iex -S mix)-.ex,如果该代码也(或可能将)被应用程序使用; .exs 用于“临时”脚本,例如针对特定错误或其他问题
          3. 从 shell,通过 mix.ex 用于自定义 Mix 任务,或作为 mix.exs 中的数据(用于简单任务别名)
          4. 从 shell,即作为“常规脚本” - .exs 并通过 elixir some-script.exs 运行。

          令人惊讶的是,以 [2]、[3] 或 [4] 之一开头的一段好代码,最终还是以 [1] 结尾。

          要记住的一件非常重要的事情是,从例如移动代码很容易。将.exs 文件转换为.ex 文件(反之亦然)。

          对于 [2],特别是对于一个应用程序,我设置了一些额外的“脚本模式”混合环境以用于 iex。基本上,它们运行应用程序(部分)的基本“开发”本地实例,但连接到生产/暂存数据库(或其他后端服务)。我有一些用于这些“命令环境”的辅助函数/宏,但大多数情况下我只是使用应用程序代码,例如查询生产/登台数据库并修复/清理/检查一些数据。如果我确实需要做一些甚至有点“涉及”(复杂)的事情,我通常会创建一个临时的“问题脚本”。在我的编辑器中编写代码比在iex 中容易得多。

          对于 [2] 的临时脚本,我在一个项目中有一个 dev/scripts 子目录树,并且大多只是根据相应的票号(来自该项目的票证系统)命名临时脚本,例如. 123.exs。然后,在iex 中,我可以轻松运行该脚本:

          iex> c "dev/scripts/123.exs"
          

          一个不错的“工作流程”是在脚本文件中定义一个(顶级)模块:

          defmodule Ticket123 do
          
            ...
          
            def do_some_one_off_thing ...
          
          end
          

          然后,来自iex

          iex> c "dev/scripts/123.exs"
          [Ticket123]
          iex> Ticket123.do_some_one_off_thing ...
          Something something
          ...
          

          对于 [3],您项目的 mix.exs 和“完全”自定义 Mix 任务中的任务别名都非常好。

          来自一个项目的一些示例别名:

          • 运行“所有”迁移——这个项目有常规的 (Ecto) 数据库迁移和一些我们想要“手动”运行的迁移(即使用上面提到的“脚本模式”环境)。我们对长时间运行的数据库查询/命令等事情使用手动迁移,例如。在大表上添加或修改索引。
          • 部署到登台/生产
          • test – 这隐藏了内置 Mix 任务以执行一些自定义本地数据库设置
          • todo – 在我们的 (Elixir) 代码中输出 TODO cmets 的搜索结果

          来自同一项目的一些示例自定义任务:

          • Mix.Tasks.OneProject.BootstrapServer – 一些自定义{配置管理/自动化基础设施部署}代码
          • Mix.Tasks.OneProject.DbSetup – 从 Elixir 应用程序中提取一些配置数据,但大多只是将其传递给 shell 脚本
          • Mix.Tasks.OneProject.ImportTranslations – 从第三方下载翻译和其他国际化数据
          • Mix.Tasks.OneProject.RollingDeploy – 使用类似于“蓝绿”模型的自定义部署,但使用负载均衡器而不是两个完全独立的环境/实例

          我在任何项目中都没有使用过完全“常规”的 Elixir 脚本文件——通过elixir some-script.exs 调用。可能最大的原因是不创建自定义 Mix 任务或“问题脚本”,即自定义 Mix 任务有很好的文档记录,即通过 mix helpmix help some-custom-mix-task,我 真的 喜欢在 REPL (iex) 工作。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-11-07
            • 2015-02-18
            • 2012-03-13
            • 2015-01-07
            • 2016-09-23
            • 2021-02-09
            • 2019-08-12
            相关资源
            最近更新 更多