我想要一个包含“操作”字段的数据库表。我想在现场存储一个 Elixir 函数。这可能吗?
该函数始终只接受一个参数。
最佳答案
这是我过去使用过的一种 Ecto 类型,它与上面评论中链接的 @AbM 非常相似:
defmodule ErlangETF do
def type, do: :binary
def cast(binary = << 131, _ :: binary >>) do
try do
{:ok, :erlang.binary_to_term(binary)}
catch
_ ->
{:ok, binary}
end
end
def cast(any), do: {:ok, any}
def load(any), do: cast(any)
def dump(any), do: {:ok, :erlang.term_to_binary(any)}
end
模型的架构定义可能如下所示:
defmodule Example do
use Ecto.Model
schema "examples" do
field :function, ErlangETF
end
end
如果您想进一步限制允许的术语类型(例如,仅允许元数为 1 的函数),类似这样的操作可能会起作用:
defmodule ErlangFunctionArity1ETF do
def type, do: :binary
def cast(binary = << 131, _ :: binary >>) do
try do
case :erlang.binary_to_term(binary) do
function when is_function(function, 1) ->
{:ok, function}
_ ->
{:ok, binary}
end
catch
_ ->
{:ok, binary}
end
end
def cast(any), do: {:ok, any}
def load(any), do: cast(any)
def dump(function) when is_function(function, 1),
do: {:ok, :erlang.term_to_binary(function)}
def dump(_),
do: {:ok, nil}
end
您还可以在外部术语格式中存储两种格式的函数:
以下是 EXPORT_EXT
和生成的字节大小的示例:
iex> (&Enum.sum/1) |> ErlangFunctionArity1ETF.dump |> elem(1) |> byte_size
24
以下是 NEW_FUN_EXT
和生成的字节大小的示例:
iex> (fn c -> Enum.sum(c) end) |> ErlangFunctionArity1ETF.dump |> elem(1) |> byte_size
228
我提到了字节大小差异,以防存储大小成为问题。
EXPORT_EXT
本质上只存储 2 个原子和 1 个整数(:Enum
、:sum
和 1
)这就是序列化函数的大小如此之小的原因。匿名函数被序列化为 NEW_FUN_EXT
,它存储所有函数代码及其创建信息。
关于elixir - 如何在 Ecto 中存储 Elixir 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34079938/