Elixir 我可以将管道和更新语法与结构一起使用吗?
我发现我想经常更新一个结构,然后通过管道将结果传递给另一个函数。更新我的结构的需要不断破坏我的管道 我发现自己经常这样做:Elixir 我可以将管道和更新语法与结构一起使用吗?,elixir,Elixir,我发现我想经常更新一个结构,然后通过管道将结果传递给另一个函数。更新我的结构的需要不断破坏我的管道 我发现自己经常这样做: 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
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(),但是我必须在模块中编写一个函数,将生成的映射转换回我的结构类型
以前有人遇到过这种小麻烦吗?有没有干净的替代方法?如果您确实想:
my_struct
|> (&(%{ &1| my_field_in_struct: a_new_value})).()
或
但我认为这看起来不太好/可读如果您真的想:
my_struct
|> (&(%{ &1| my_field_in_struct: a_new_value})).()
或
但我认为这看起来不太好/可读长生不老药的真正优点是它有宏。那么,如果这是应用程序中非常常见的操作,为什么不定义自己的管道操作符呢
defmodule-StructPipe-do
defmacro left~>>右do
{:%{},[],[{:|,[],[左,右]}
终止
终止
解除模块MyStruct do
defstruct~w|foo bar baz|a
终止
defmodule StructPipe.testdo
导入结构管道
def测试do
%MyStruct{foo:42}
~>>[bar:3.14]
~>>[baz:“FOOBAR”]
终止
终止
IO.inspect.Test.Test,标签:“导致”
#⇒结果是:%MyStruct{bar:3.14,baz:“FOOBAR”,foo:42}
请注意,它可能与普通管道安全混合:
%MyStruct{foo:42}
|>IO.检查(标签:“Ini”)
~>>[bar:3.14,baz:3.14]
|>IO.检查(标签:“Mid”)
~>>[baz:“FOOBAR”]
|>IO.检查(标签:“船尾”)
#⇒ Ini:%MyStruct{bar:nil,baz:nil,foo:42}
#Mid:%MyStruct{bar:3.14,baz:3.14,foo:42}
#船尾:%MyStruct{bar:3.14,baz:“FOOBAR”,foo:42}
长生不老药真正伟大之处在于它有宏。那么,如果这是应用程序中非常常见的操作,为什么不定义自己的管道操作符呢
defmodule-StructPipe-do
defmacro left~>>右do
{:%{},[],[{:|,[],[左,右]}
终止
终止
解除模块MyStruct do
defstruct~w|foo bar baz|a
终止
defmodule StructPipe.testdo
导入结构管道
def测试do
%MyStruct{foo:42}
~>>[bar:3.14]
~>>[baz:“FOOBAR”]
终止
终止
IO.inspect.Test.Test,标签:“导致”
#⇒结果是:%MyStruct{bar:3.14,baz:“FOOBAR”,foo:42}
请注意,它可能与普通管道安全混合:
%MyStruct{foo:42}
|>IO.检查(标签:“Ini”)
~>>[bar:3.14,baz:3.14]
|>IO.检查(标签:“Mid”)
~>>[baz:“FOOBAR”]
|>IO.检查(标签:“船尾”)
#⇒ Ini:%MyStruct{bar:nil,baz:nil,foo:42}
#Mid:%MyStruct{bar:3.14,baz:3.14,foo:42}
#船尾:%MyStruct{bar:3.14,baz:“FOOBAR”,foo:42}
这里怎么了?结构在下面是裸露的Map
s和Map。put/3
将保留一个\uuuuuuuuuuuuuuuuu
键。“我知道我可以使用Map.put(),但我必须在模块中编写一个函数,将生成的映射转换回我的结构类型。”不,你不会。您可以使用Map。将
放在任何结构上,只要您不修改\uuuuuuuuuuuuuuuuuuuu
字段,您就会得到一个结构。(结构只不过是一个带有\uuuu struct\uuuu
字段的映射。)哦,你说得对!我不知道为什么我认为这不管用。这里怎么了?结构在下面是裸露的Map
s和Map。put/3
将保留一个\uuuuuuuuuuuuuuuuu
键。“我知道我可以使用Map.put(),但我必须在模块中编写一个函数,将生成的映射转换回我的结构类型。”不,你不会。您可以使用Map。将
放在任何结构上,只要您不修改\uuuuuuuuuuuuuuuuuuuu
字段,您就会得到一个结构。(结构只不过是一个带有\uuuu struct\uuuu
字段的映射。)哦,你说得对!我不确定为什么我认为这不起作用。为一个简单导入该模块的模块定义use
,是一种反模式。告诉用户只需导入模块即可还要注意,~>>
不需要是宏。它也可以是一个函数:def left~>>right,do:Enum.into(right,left)
@JoséValim需要可收集的
,默认情况下,该函数不用于结构。谢谢,import
而不是use
是固定的。为简单导入该模块的模块定义use
是一种反模式。告诉用户只需导入模块即可还要注意,~>>
不需要是宏。它也可以是一个函数:def left~>>right,do:Enum.into(right,left)
@JoséValim需要可收集的
,默认情况下,该函数不用于结构。谢谢,导入
而不是使用
已修复。