二进制类型上的模式匹配不能使用变量的值

时间:2018-08-17 18:44:36

标签: erlang elixir

例如:

arg = "echo:hello"
prefix = "echo"

case arg do
  <<^prefix, ":", msg::binary>> -> IO.puts("Echo message: #{msg}")
  _ -> IO.puts("No match")
end

结果:No match

如果我想使用prefix的值作为模式匹配怎么办?

1 个答案:

答案 0 :(得分:8)

这将不起作用,因为如果不匹配字符串的“其余”,则只能匹配固定大小的二进制文件。共有3种解决方案,具体取决于您的用例

1。预先计算大小

如果您确实要使用该二进制模式匹配,则可以事先手动计算大小:

arg = "echo:hello"
prefix = "echo"
prefix_size = byte_size(prefix)

case arg do
  <<^prefix::binary-size(prefix_size), ":", msg::binary>> -> IO.puts("Echo message: #{msg}")
  _ -> IO.puts("No match")
end

2。使用编译时模块属性

根据您的用例,您可以使用模块属性,该属性在编译时已知,因此它们可以正常工作:

defmodule MyModule do

  @prefix "echo"

  def test(arg) do
    case arg do
      <<@prefix::binary, ":", msg::binary>> -> IO.puts("Echo message: #{msg}")
      _ -> IO.puts("No match")
    end
  end
end

3。使用String.replace_prefix / 3

或者,如果您想保留prefix的运行时二进制文件,则可以使用String.replace_prefix/3

arg = "echo:hello"
prefix = "echo"

case String.replace_prefix(arg, "#{prefix}:", "")do
  ^arg -> IO.puts("No match")
  msg -> IO.puts("Echo match: #{msg}") 
end

String.replace_prefix/3如果找不到匹配项,则返回输入字符串,因此我们通过^arg对其进行匹配。如果不是这种情况,我们将得到一个匹配,并且由于我们将前缀替换为"",因此我们只得到了:之后的部分。