为什么在Ecto查询中需要引脚操作符?

use*_*006 26 elixir ecto

在Elixir中,引脚运算符用于防止变量重新绑定.但是,对于像Ecto这样的查询

from u in User, where: u.username == ^username
Run Code Online (Sandbox Code Playgroud)

的作者编程凤凰状态(第7章),其

请记住,^运算符(称为pin运算符)意味着我们希望保持^ username相同.

但这听起来不对,因为显然,查询中的比较不会导致任何重新绑定变量.

这本书的作者(JoséValim与谁合着)是错误的吗?Ecto中的引脚运算符只是查询Ecto DSL的构造而不是通常的Elixir引脚运算符吗?或者username,在宏扩展后,查询是否真的有机会重新绑定?

Mla*_*vić 27

Ecto的查询依赖于宏来提供我们使用的强大的DSL.这意味着,无论发生什么from,都不是"常规"Elixir代码,而是最终将转换为SQL查询的DSL.因此,插入符号本身没有插入操作符,与模式匹配无关(尽管显然它仍然可以称为"引脚操作符",因为人们总是会忘记诸如插入符号符号星号之类的单词).这只是一个方便的操作员,Ecto的作者选择成为"插值算子".如果没有它,username你的示例将从字面上直接插入,并直接插入到生成的SQL中(尽管Ecto足够聪明,可以看到那不是你想要的,所以它会溢出错误).

很棒的问题BTW,激励我阅读更多关于宏(FP中的新手).

  • 谢谢你的解释!我真的很难通过 Elixir 的镜头来理解 Ecto 的查询语法,但知道它是基于宏构建的 DSL 使得语法更容易理解。 (2认同)

Nim*_*mir 22

根据Ecto文档,ecto中的pin运算符用于查询插值:

可以使用^将外部值和Elixir表达式注入查询表达式

def with_minimum(age, height_ft) do
  from u in "users",
    where: u.age > ^age and u.height > ^(height_ft * 3.28),
    select: u.name
end
Run Code Online (Sandbox Code Playgroud)

试图跳过引脚会给你一个错误,因为Ecto无法找出一个名为的数据库函数或查询表达式age:

(Ecto.Query.CompileError)变量age不是有效的查询表达式.需要使用^在查询中显式插值变量