我希望有一个数据库表,其中有一个' action'领域。我想在现场存储Elixir功能。这可能吗?
该功能始终只接受一个参数。
答案 0 :(得分:2)
这是我过去使用的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
如果你想进一步限制允许的术语类型(例如,只允许arity为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
NEW_FUN_EXT
以下是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
,它存储了所有函数代码以及有关其创建的信息。
答案 1 :(得分:0)
这是一种将函数序列化为字符串并反序列化的快速方法。
iex(1)> defmodule Test do
...(1)> def test(num), do: {:ok, num}
...(1)> end
{:module, Test,
<<70, 79, 82, 49, 0, 0, 4, 224, 66, 69, 65, 77, 69, 120, 68, 99, 0, 0, 0, 147,
131, 104, 2, 100, 0, 14, 101, 108, 105, 120, 105, 114, 95, 100, 111, 99, 115,
95, 118, 49, 108, 0, 0, 0, 4, 104, 2, ...>>, {:test, 1}}
iex(2)> save = "#{Test} #{:test}"
"Elixir.Test test"
iex(3)> [mod, fun] = String.split(save, " ") |> Enum.map(&String.to_existing_atom/1)
[Test, :test]
iex(4)> apply mod, fun, [10]
{:ok, 10}