【问题标题】:Checking Erlang OTP Release to execute different functions on Elixir检查 Erlang OTP Release 以在 Elixir 上执行不同的功能
【发布时间】:2021-12-31 14:35:40
【问题描述】:

我正在创建一个新的 Elixir 库,需要使用不同版本的语言来执行。

这个库使用 Erlang :crypto.hmac 函数,但是这个函数在 Erlang OTP 的第 22 版上被 :crypto.mac 取代(具有相同的功能)。

我正在使用以下私有宏来执行较新或较旧的功能:

defmacrop hmac(key, data) do
  if System.otp_release() >= "22" do
    quote do: :crypto.mac(:hmac, :sha256, unquote(key), unquote(data))
  else
    quote do: :crypto.hmac(:sha256, unquote(key), unquote(data))
  end
end

并以下列方式使用它:

hmac(key, data)

两个问题:

  1. 这是基于 OTP 发行版执行代码的正确方式吗?
  2. 有什么更好的方法来解决这个问题?

谢谢。

【问题讨论】:

    标签: erlang elixir


    【解决方案1】:

    宏是编译时的生物。编译后没有宏的踪迹;相反,它注入的 AST 发生在版本中。

    也就是说,如果您希望它是编译时的,这意味着您将需要许多环境来编译,并且每个版本都可以在与仅编译时相同的平台上工作,这是正确的方法。

    如果你想组装一个版本并让它在不同的目标平台上运行,你最好使用Kernel.apply/3 as

    def hmac(key, data) do
      if String.to_integer(System.otp_release) >= 22,
        do: apply(:crypto, :mac, [:hmac, :sha256, key, data]),
        else: apply(:crypto, :hmac, [:sha256, key, data])
    end
    

    旁注:即使你希望它是编译时的,声明不同的函数会比声明宏更简洁。

    if String.to_integer(System.otp_release) >= 22 do
      def hmac(key, data),
        do: :crypto.mac(:hmac, :sha256, key, data)
    else
      def hmac(key, data),
        do: :crypto.hmac(:sha256, key, data)
    end
    

    这将在编译时进行评估,相应的函数将在生成的 BEAM 代码中执行。

    【讨论】:

    • 也许使用String.to_integer(System.otp_release) >= 22会更好
    • @Aetherus 确实,谢谢,我会更新答案。
    • 正如@Hauleth 所评论的,没有必要检查 OTP 版本。使用function_exported? 检查:crypto 模块上的可用功能是一个更好的解决方案。
    【解决方案2】:

    这是基于 OTP 发行版执行代码的正确方式吗?

    您不应检查 OTP 版本,而应检查应用程序(在本例中为 crypto)版本。因为 OTP 版本可能与应用程序版本不同。

    有什么更好的方法来解决这个问题?

    是的,检查给定函数是否被导出,而不是检查 OTP/应用程序的版本。

    在运行时有两种方法:

    def hmac(key, data) do
      if Code.ensure_loaded?(:crypto) and function_exported?(:crypto, :mac, 4) do
        :crypto.mac(:mac, :sha256, key, data)
      else
        :crypto.hmac(:sha256, key, data)
      end
    end
    

    或者在编译期间:

    if Code.ensure_loaded?(:crypto) and function_exported?(:crypto, :mac, 4) do
      def hmac(key, data), do: :crypto.mac(:mac, :sha256, key, data)
    else
      def hmac(key, data), do: :crypto.hmac(:sha256, key, data)
    end
    

    【讨论】:

    • 精彩的答案。我不知道function_exported? 功能。顺便说一句,为了正常工作,条件应该是:Code.ensure_loaded(:crypto) && function_exported?(:crypto, :mac, 4) do 如果:crypto 尚未加载,则对function_exported? 的调用将返回false。请问您能否对这两个版本进行更改,以便我可以将您的解决方案作为正确的解决方案?谢谢!
    猜你喜欢
    • 1970-01-01
    • 2019-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-06
    • 2011-08-13
    • 2013-11-18
    相关资源
    最近更新 更多