我发现我想经常更新结构,然后将结果传递给另一个函数。更新我的结构的需要不断分解我的管道。
我发现自己做了很多这样的事情:
my_struct = %{my_struct | my_field_in_struct: a_new_value} |> my_funct1
my_struct = %{my_struct | my_field_in_struct: a_new_value} |> my_funct2
my_struct = %{my_struct | my_field_in_struct: a_new_value} |> my_funct3
我想做点什么:
my_struct
|> %{ | my_field_in_struct: a_new_value}
|> my_funct1
|> %{ | my_field_in_struct: a_new_value}
|> my_funct2
|> %{ | my_field_in_struct: a_new_value}
|> my_funct3
原始语法可能不是那么糟糕,但仍然。
我知道我可以使用 Map.put(),但是我必须在我的模块中编写一个函数来将结果映射转换回我的struct类型。
之前有没有人遇到这种微小的烦恼?有没有一个干净的选择?
答案 0 :(得分:3)
Elixir有什么好处,它有宏。那么,如果这是一个非常常见的应用程序操作,为什么不定义自己的管道操作符呢?
defmodule StructPipe do
defmacro left ~>> right do
{:%{}, [], [{:|, [], [left, right]}]}
end
end
defmodule MyStruct do
defstruct ~w|foo bar baz|a
end
defmodule StructPipe.Test do
import StructPipe
def test do
%MyStruct{foo: 42}
~>> [bar: 3.14]
~>> [baz: "FOOBAR"]
end
end
IO.inspect StructPipe.Test.test, label: "Resulting in"
#⇒ Resulting in: %MyStruct{bar: 3.14, baz: "FOOBAR", foo: 42}
请注意,它可以安全地与普通Kernel.|>/2
管道混合使用:
%MyStruct{foo: 42}
|> IO.inspect(label: "Ini")
~>> [bar: 3.14, baz: 3.14]
|> IO.inspect(label: "Mid")
~>> [baz: "FOOBAR"]
|> IO.inspect(label: "Aft")
#⇒ Ini: %MyStruct{bar: nil, baz: nil, foo: 42}
# Mid: %MyStruct{bar: 3.14, baz: 3.14, foo: 42}
# Aft: %MyStruct{bar: 3.14, baz: "FOOBAR", foo: 42}
答案 1 :(得分:1)
如果确实想要:
,您也可以传入匿名函数my_struct
|> (&(%{ &1| my_field_in_struct: a_new_value})).()
或
my_struct
|> (fn struct -> %{ struct| my_field_in_struct: a_new_value} end).()
但我认为这看起来非常棒/可读