【问题标题】:What is the Erlang idiom for platform specific modules with the same contract具有相同合同的平台特定模块的 Erlang 习惯用法是什么
【发布时间】:2025-11-27 21:50:02
【问题描述】:

我有一个可以为多个平台编译的 Erlang 程序。

我想要的是为不同平台分离代码。 解决这个问题的最 Erlang 方法是什么?

我想实现这样的目标:

-module(platform_1).
-export([platform_init/0, platform_do_work/1, platform_stop/0]).
...

-module(platform_2).
-export([platform_init/0, platform_do_work/1, platform_stop/0]).
...

-module(main).
-export([start/0]).
main() ->
  platform::init(),
  platform::do_work("The work"),
  platform::stop().

(显然上面的代码不起作用,它缺少我要询问的部分。)

  1. 我可以将这两个模块命名为 platform,并在编译期间只提供其中一个。
  2. 我可以在platform 模块中使用-ifdefs 来包装特定于平台的模块。
  3. 我可以使用-behavior 指定一个通用合同。
  4. 我可以使用带有-export 宏的头文件来提供通用合约。

我确信还有其他解决方案。我只是没有为这个一般用例找到任何成语。

【问题讨论】:

    标签: erlang idioms


    【解决方案1】:

    我的第一反应是define a new behavior,比如:

    -module platform.
    
    -type state() :: term().
    -type work() :: {some, work} | ….
    
    -callback init() -> {ok, state()}.
    -callback do_work(work(), state()) -> {ok, state()}.
    -callback stop(state()) -> ok.
    
    -export([run/1]).
    
    -spec run(module()) -> ok.
    run(Module) ->
      {ok, State0} = Module:init(),
      {ok, State1} = Module:do_work({some, work}, State0),
      ok = Module:stop(State1).
    

    然后,您的模块可以实现该行为(我可能会将它们放在像 src/platforms 这样的文件夹中,它们看起来像......

    -module first_platform.
    -behavior platform.
    -export [init/0, do_work/2, stop/1].
    
    -spec init() -> {ok, platform:state()}.
    init() –>
      …,
      {ok, State}.
    …
    

    你的主模块可以有一个宏或一个环境变量,或者它可以检索要使用的平台的东西,看起来像......

    -module main.
    -export [start/0].
    
    -spec start() -> ok.
    start() ->
      Platform =
        application:get_env(your_app, platform, first_platform),
      platform:run(Platform).
    

    甚至……

    -module main.
    -export [start/0].
    
    -spec start() -> ok.
    start() ->
      platform:run().
      
    

    ...然后您找出platform 中使用哪个平台。

    【讨论】:

      【解决方案2】:

      实现您想要的一个简单方法是将模块存储在一个变量中,并使用该变量调用正确的模块/函数。

      例如,您可以使用选择正确平台的额外参数来启动您的应用程序:

      erl [your parameters] -extra "platform=platform_1"
      

      根据需要定义与平台相关的模块

      -module(platform_1).
      -export([platform_init/0, platform_do_work/1, platform_stop/0]).
      ...
      

      -module(platform_2).
      -export([platform_init/0, platform_do_work/1, platform_stop/0]).
      ...
      

      并在主函数中检索平台参数

      -module(main).
      -export([start/0]).
      main() ->
        Args = init:get_plain_arguments().
        [Platform] =
          [list_to_atom(lists:nthtail(9,Y))
          || Y <- Args, string:prefix(Y,"platform=") =/= nomatch].
        Platform:init(),
        Platform:do_work("The work"),
        Platform:stop().
      

      我根本不相信这是最好的方法,主要是因为你需要知道,当你使用一个模块时,它是否依赖于平台(并且获取平台的代码不干净)。

      我认为如果模块本身负责平台选择会更好。我会在有空的时候尽快完成这个答案。

      【讨论】:

        最近更新 更多