【问题标题】:Are Erlang behaviours really kind of the same as class inheritance?Erlang 的行为真的和类继承一样吗?
【发布时间】:2020-06-02 05:41:21
【问题描述】:

目前我正在使用 Apache Kafka 和 Erlang 作为流处理器语言进行数据管道项目(实际上,除了从年初开始学习语言和概念外,我之前没有使用 erlang 的经验)。要编写 Kafka 消费者,我们依赖坚如磐石的 brod 模块。

我明白,我必须编写一个主管回调模块,负责启动我的 brod_client 和我的 group_consumer 模块。

my_app
  +-- my_sup
        +-- brod_client
        +-- my_group_consumer

我编写的这个 group_consumer 模块是 brod_group_subsriber_v2 行为的回调模块,它本身就是 gen_server 的回调模块。

my_group_consumer > brod_group_subscriber > gen_server

当我运行我的应用程序时,我的主管正在启动 brod_client,但不是我的消费者 erlang:whereis(my_group_consumer). 返回 undefined。只有在消息到达后,brod_group_consumer_v2 本身似乎才会初始化 my_group_consumer 并调用其消息处理函数。这种“惰性”初始化对我来说是有意义的,但与我所期望的不同,因为我将主管配置为明确地处理 my_group_consumer(而不是它的基本行为)。

因此,毕竟我不确定我是否完全理解行为,因此我是否正确使用了 brod 模块,因为我尝试从它们继承,就像我使用 Java 类继承和多态一样。

很难找到在主管中使用 brod 的示例,而不仅仅是在 shell 上用于演示目的。

编辑:我在这里使用 brod 作为情况/用例的示例,我希望大多数专业模块的实现从 mst 通用模块“继承”,这似乎并非如此,因此我无法正确使用像 brod 这样的模块。

有人能解释一下这些概念的区别吗?如果你想根据我的例子来解释它会很棒,如果你能用另一个例子或根本没有例子来解释它......也很好,提前谢谢。

【问题讨论】:

  • 你最后的问题似乎与标题基本无关。
  • 你是对的!我进行了编辑以明确说明,小消费者应该只是一个例子……我正在询问有关解释这些概念以及它们如何映射在一起的建议。

标签: apache-kafka erlang kafka-consumer-api behavior erlang-supervisor


【解决方案1】:

就像@alexey-romanov 在评论中所说,我相信您最终会遇到一个与标题中的问题截然不同的问题。 尽管如此,如果你仍然对学习如何理解 Erlang/Elixir 行为感兴趣,我在不久前写了twoarticles 并给了a talk about it on CodeBEAM SF 2019。 希望这会有所帮助:)

【讨论】:

  • 在你的第二篇文章中,你写的最后一句话 > "5. 使用现有行为 最后,记住你不需要每次都从头开始。同一个模块可以是一个回调模块行为并定义另一种行为。如果现有行为将您带到了一半,您可以在其上构建新行为,就像 OTP 所做的那样;)" ...我希望有第三篇文章完全涵盖这一点;)
  • 我看看能不能写出来。无论如何,wpool (hex.pm/packages/worker_pool) 就是一个很好的例子……通过它,您可以使用 gen_server 接口构建一个池。
【解决方案2】:

同一个模块可以是一个行为的回调模块并定义 其他。如果一个现有的行为把你带到了一半,你可以 就像 OTP 一样,在它之上建立你的新行为;)"

...我希望有第三篇文章完全涵盖这一点;)

以下示例适用于我——它在 gen_server 之上实现了 my_server 行为:

my_server.erl:

-module(my_server).
-compile(export_all).

-behaviour(gen_server).
-callback go( integer() ) -> atom().  %% Specifies that this module is a behaviour
                                      %% which has one required callback function go/1

%%%   required gen_server callback functions

init(_Args) ->
    {ok, []}.

handle_call(Msg, _From, State) ->
    io:format("In handle_call(), Msg= ~w~n", [Msg]),
    {reply, hello_from_handle_call, State}.

handle_cast(Msg, State) ->
    io:format("In handle_cast(), Msg= ~w~n", [Msg]),
    {noreply, State}.

handle_info(Msg, State) ->
    io:format("In handle_info(), Msg= ~w~n", [Msg]),
    {noreply, State}.

b.erl:

-module(b).
-compile(export_all).

-behaviour(my_server).

%%  my_server callback functions

go(_Count) ->
    ?MODULE ! hi_from_go,  %% handle_info() gets this message
    hi.

%% client functions

start() ->
    gen_server:start_link( %% Calls the init() gen_server callback function.
      {local, ?MODULE},    %% Registers the gen_server using this name.
      my_server,           %% Looks for the gen_server callback functions in this module.
      [],
      []
    ).

do_call() ->
    spawn(
      fun() -> gen_server:call(?MODULE, hello) end  %% handle_call() gets this message
    ).

do_go() ->
    spawn(
      fun() -> go(20) end
    ).

在外壳中:

1> c(my_server).
my_server.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my_server}

2> c(b).
b.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,b}

3> b:start().
{ok,<0.76.0>}

4> b:do_call().
In handle_call(), Msg= hello
<0.78.0>

5> b:do_go().
In handle_info(), Msg= hi_from_go
<0.80.0>

【讨论】:

  • 谢谢,这澄清了我的问题,并且对我来说也可以重现
猜你喜欢
  • 2022-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-25
  • 1970-01-01
  • 1970-01-01
  • 2018-11-10
  • 1970-01-01
相关资源
最近更新 更多