简体   繁体   English

Elixir 返回实现者结构类型的行为

[英]Elixir Behaviour that returns the implementer's struct type

I have a behaviour to abstract over parsing URL query parameters for various Phoenix endpoints.我有一种行为来抽象解析各种 Phoenix 端点的 URL 查询参数。 It looks like this:它看起来像这样:

defmodule Query do
  @callback from_query_params(params :: %{optional(String.t()) => any()}) ::
              {:ok, parsed :: struct} | {:error, reason :: atom}
end

And a simple implementation looks like this:一个简单的实现如下所示:

defmodule SearchQuery do
  @moduledoc "Parses URL query params for search endpoint"
  @behaviour Query

  @enforce_keys [:search_term]
  defstruct @enforce_keys

  @typespec t :: %__MODULE__{search_term: String.t()}

  @impl Query
  def from_query_params(%{"query" => query}) when query != "" do
    {:ok, %__MODULE__{search_term: query}}
  end

  def from_query_params(_), do: {:error, :missing_search_term}
end

What I'd really like to say here is:我在这里真正想说的是:

  • The implementing module should provide a struct (call it t() )实现模块应该提供一个结构(称之为t()
  • The success type on from_query_params/1 should use that struct t() , not just any struct from_query_params/1上的成功类型应该使用结构t() ,而不仅仅是任何结构

I suspect there's no way within the Elixir typespec language to express this, but I'd be delighted to be proven wrong.我怀疑 Elixir 类型规范语言中没有办法表达这一点,但我很高兴被证明是错误的。

While it's impossible to express this in typespec, one might partially cover the requirements with a bit of metaprogramming.虽然不可能在 typespec 中表达这一点,但可以通过一些元编程来部分覆盖需求。

If you are ok with having its own Query behaviour per implementation to distinguish return types, it could be done with如果您对每个实现都有自己的Query行为来区分返回类型感到满意,则可以使用

defmodule QueryBuilder do
  defmacro __using__(opts \\ []) do
    quote do
      impl = __MODULE__
      defmodule Query do
        @callback from_query_params(map()) :: {:ok, %unquote(impl){}}

        def __after_compile__(env, _bytecode),
          do: env.module.__struct__
      end

      @behaviour Query
      @after_compile Query
    end
  end
end

And instead of @behaviour Query , use use QueryBuilder .而不是@behaviour Query ,使用use QueryBuilder That way the nested Query module will have a proper return type and the compiler callback will raise if the target module does not declare the struct.这样,嵌套的Query模块将具有正确的返回类型,并且如果目标模块未声明结构, 编译器回调将引发。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM