为什么禁止在警卫内部使用远程功能

时间:2016-01-18 08:25:56

标签: elixir

为什么我无法使用String或其他模块进行保护?

代码:

def foo(s1, s2) when String.length(s1) == String.length(s2) do 
   # something
end

当我希望使用模块功能时,如何优雅地重新格式化这种情况?

2 个答案:

答案 0 :(得分:24)

来自erlang docs

  

有效保护表达式集(有时称为保护测试)是有效Erlang表达式集的子集。限制有效表达式集的原因是必须保证对保护表达式的评估没有副作用。

Elixir也是如此。

好消息是,对于您的特定用例,有一个可以工作的警卫:

def foo(s1, s2) when byte_size(s1) == byte_size(s2) do 

通常,当您想要做的事情无法在警卫中使用时,您需要检查该功能,例如:

def foo(s1, s2) do 
  cond do 
    String.length(s1) == String.length(s2) -> # Do something
    true                                   -> # Do something else
  end
end

以下答案解释了用宏Create new guard clause定义自己的守卫(守卫必须使用http://elixir-lang.org/getting-started/case-cond-and-if.html#expressions-in-guard-clauses中记录的有效守卫功能)

答案 1 :(得分:1)

byte_size(s1) == byte_size(s2)

的含义不同
String.length(s1) == String.length(s2)

仅对由单个字节组成的字符执行此操作。

iex(1)> String.length("hello") == String.length("helló")
true
iex(2)> byte_size("hello") == byte_size("helló")
false

要获得正确的行为,您必须手动调度:

def foo_same(s1, s2) do 
   # something
end

def foo_different(s1, s2)do 
   # something
end

def foo(s1, s2) do
  if String.length(s1) == String.length(s2) do
    foo_same(s1, s2)
  else
    foo_different(s1, s2)
  end
end