说我目前有这样的东西:
session = conn.assigns[:session]
user = User.find_by_id(session.user_id)
如何在此场景中使用|> sytle?
conn.assigns[:session]
|>User.find_by_id
如何传递先前的呼叫并从中获取属性user_id?
我还看到人们使用|>,并且我认为他们也在指定Arity,这是如何工作的?
some_code
|> some_function(&/2)
类似的事情,我不记得了,但是看着它我很困惑。
答案 0 :(得分:2)
我认为您可能最好在函数头上进行模式匹配,并从那里的赋值中提取user_id
,说过您可以使用Map.fetch!/2
,如下所示:
conn.assigns[:session]
|> Map.fetch!(:user_id)
|> User.find_by_id
但是,正如您看到的那样,当您从映射转到单个值到架构结果时,管道的含义变得有些混乱。 IMO不会提高可读性或意图。
您也可以使用conn.assigns.session.user_id |> User.find_by_id
。
如果缺少任何中间字段,所有这些操作都会失败,但是如果您在功能头上进行模式匹配(我假设它在控制器中),则可以设置后备操作或捕获所有返回错误的操作。
答案 1 :(得分:2)
第一部分-您可以像这样使用管道:
conn.assigns[:session]
|> Map.get(:user_id) # Use function from Map module.
|> User.find_by_id()
第二部分。您看到Capture operator
您可以将其与需要匿名函数作为参数的函数一起使用(它是模块的本地函数或远程函数)
让我们以Ecto.Changeset.validate_change/3
为例因此,第三个参数需要一个匿名函数(验证器),该函数具有2个参数,您可以在模式中编写一个私有函数,以在传递给变更集并使用它时验证更改:
defp validate_title(field, title) do
if title == "foo" do
[{field, "cannot be foo"}]
else
[]
end
end
因此,当您使用更改集验证它时,您可以执行以下操作:
changeset = change(%Post{}, %{title: "foo"})
changeset = validate_change(changeset, :title, &validate_title/2)
答案 2 :(得分:2)
在这种情况下如何使用
|>
风格?
有数十种不同的方法。正确的答案是在这种情况下您不使用管道运算符。因此,它被称为管道运算符。它打算用于管道。
Elixir核心团队认为在声明中使用单个|>
是反模式。您应该改用
user = User.find_by_id(conn.assigns[:session].user_id)
另一方面,如果您确实想在此处使用|>
,则可以使用Access
行为:
user =
conn.assigns
|> Map.get(:session)
|> Map.get(:user_id)
|> User.find_by_id()
答案 3 :(得分:1)
|>
取其上方(或其左侧)的内容,并将该表达式的值作为第一个参数传递给您在管道右侧调用的函数。这就是管道的全部工作。因此,您尝试在此处使用管道:
conn.assigns[:session]
|>User.find_by_id
等效于:
User.find_by_id(
conn.assigns[:session]
)
这是另一个例子:
defmodule My do
def package({x, y}) do
%{width: x, length: y}
end
def modify(map, z) do
Map.put_new(map, :height, z)
end
def go(tuple) do
tuple
|> package()
|> modify(10)
end
end
在iex中:
~/elixir_programs$ iex c.exs
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Interactive Elixir (1.6.6) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> My.go {1, 2}
%{height: 10, length: 2, width: 1}
在My.go()
定义中,为tuple
参数变量分配了参数{1, 2}
,从而获得了以下管道:
{1, 2}
|> package()
|> modify(10)
第一个管道导致package()
被第一个参数{1, 2}
调用,因此package({1, 2})
会返回
%{width: 1, length: 2}
留下您:
%{width: 1, length: 2}
|> modify(10)
然后管道导致调用modify()
,第一个参数为%{width: 1, length: 2}
,因此modify(%{width: 1, length: 2}, 10)
,返回:
%{height: 10, length: 2, width: 1}
我也看到人们使用|>,我认为他们也在指定 阿里,这是怎么工作的?
some_code |> some_function(&/2)
&
用于几种不同的事物。首先,&
将根据您指定的表达式创建一个匿名函数:
my_func = &(3*4)
这将创建匿名函数:
my_func = fun -> 3*4 end
嗯,不完全是。这实际上是行不通的,因为&
要求&
之后的表达式至少使用一个函数参数变量。功能参数变量?这是&
的第二种用法。匿名函数的(未指定)参数变量可以在表达式中使用名称&1,&2,&3等进行引用。所以你必须写:
my_func = &(3 * &1)
这将创建匿名函数:
fn x -> 3 * x end
匿名函数具有Arity 1,因为在表达式中仅提及&1
。如果在表达式中提到&1
和&2
,则创建的函数的对数为2:
iex(5)> my_func = &(IO.puts "#{&2} ... #{&1}")
#Function<12.99386804/2 in :erl_eval.expr/5>
iex(6)> my_func.("hello", "world")
world ... hello
如果您在表达式中提到&1
和&3
,而省略了&2
,则会出现错误消息:
没有&2不能定义捕获&3。
您还可以使用&
创建包装现有功能的匿名功能:
len = &Enum.count/1
len.([7,8,9])
=> 3
&
创建匿名函数:
fun x -> Enum.count(x) end
要求您通过指定现有功能的名称和名称来唯一标识其功能。对于本地函数或导入的函数,只需编写&func_name/2
并消除模块名称即可。