Elixir管道操作符调用Repo.preload报错:preload/1未定义问题咨询
问题原因与解决方案
这个问题的核心是Elixir操作符的优先级问题——点操作符(.)的优先级比管道操作符(|>)更高,导致你的管道写法被解析成了错误的函数调用。
具体解析差异
先看能正常运行的代码:
a1 = Repo.get_by(MyModel, var1: var1) a2 = Repo.preload(a1, [:aaa, bbb: :ccc]).items
这里的执行逻辑是:
- 先通过
Repo.get_by/2获取到a1 - 把
a1作为第一个参数传给Repo.preload/2(第二个参数是预加载的关联列表),得到预加载后的结构体 - 最后访问这个结构体的
items属性,赋值给a2
而你的管道写法:
Repo.get_by(MyModel, var1: var1) |> Repo.preload([:aaa, bbb: :ccc]).items
由于点操作符优先级更高,Elixir会先尝试执行Repo.preload([:aaa, bbb: :ccc])——这相当于只给Repo.preload传了一个参数,调用的是不存在的preload/1函数,而Repo只提供了preload/2和preload/3(需要第一个参数是要预加载的结构体/查询,第二个是关联列表),所以直接抛出了UndefinedFunctionError。
修正后的管道写法
你可以用两种方式修正这个问题:
方式1:使用then/2明确执行顺序
then/2会把管道前的结果作为参数传入匿名函数,能清晰控制执行流程:
Repo.get_by(MyModel, var1: var1) |> then(&Repo.preload(&1, [:aaa, bbb: :ccc]).items)
方式2:拆分管道步骤
把预加载和属性访问拆成两个管道步骤,可读性更高:
Repo.get_by(MyModel, var1: var1) |> Repo.preload([:aaa, bbb: :ccc]) |> then(& &1.items) # 或者用Map.get更安全(避免结构体没有items时崩溃) Repo.get_by(MyModel, var1: var1) |> Repo.preload([:aaa, bbb: :ccc]) |> Map.get(:items)
内容的提问来源于stack exchange,提问作者Kojiru
相关产品推荐
相关产品推荐

