我正在努力想出一个在Elixir中进行输入验证的简洁方法。
在OOP语言中我会做这样的事情:
def my_func(a, b):
if !validate_a(a):
raise ArgumentError
if !validate_b(b):
raise ArgumentError
return "something"
Elixir中我能想到的最好的是:
def my_func(a, b) do
cond do
not valid_a?(a) -> {:error, "a is invalid"}
not valid_b?(b) -> {:error, "b is invalid"}
:otherwise -> {:ok, "something"}
end
end
我知道我也可以在Elxir中引发一个异常,但我更喜欢对返回类型进行模式匹配,因为我的代码并没有被try / rescue块搞得一团糟。
在Elixir中是否有首选模式?
答案 0 :(得分:4)
一切都取决于验证后 以及您希望验证的种类。
例如:如果您只是验证a
而b
是整数,则可以在函数定义中使用guard
子句。
def my_func(a, b) when is_integer(a) and is_integer(b) do
# your code - validation passed
end
def my_func(_, _) do
# validation failed
end
在自定义验证方面,最好有单独的功能,您可以在“主”功能中使用它 - 您的代码更清晰,更容易测试,因为它更好地隔离。在您的情况下 - 具有验证的cond
可能具有不同的功能。
在处理Phoenix控制器中的验证时,您显然可以创建自己的Plugs,当您在Ruby on Rails控制器中使用类似before
时,这非常方便。
答案 1 :(得分:1)
根据验证的复杂程度和数据的外观,即使您不打算存储数据,也可以选择使用Ecto.Changeset
。
非常简单,如下所示
defmodule Foo do
use Ecto.Schema
import Ecto.Changeset
schema "my_schema" do
field :name, :string
field :age, :integer
end
def changeset(struct, params) do
struct
|> cast(params, [:name, :age])
|> validate_required([:name, :age])
|> validate_number(:age, greater_than: 18)
end
end
运行changeset/2
功能后,系统会为您Ecto.Changeset
提供一个valid?
字段。如果是这样,它会通过所有验证。如果它是错误的,它还会从变更集的:errors
键中告诉您原因。