You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何配置让Elixir模块的__info__函数正常可用?

问题:调用Elixir模块__info__函数触发FunctionClauseError的解决方法

复现场景

IEx执行日志

iex(2)> Mirror.Imports.Product
Mirror.Imports.Product
iex(3)> Mirror.Imports.Product.parse_description("aaaa")
[]
iex(4)> Mirror.Imports.Product.__info__(:attribute)
** (FunctionClauseError) no function clause matching in Mirror.Imports.Product.__info__/1

The following arguments were given to Mirror.Imports.Product.__info__/1:

    # 1
    :attribute

(mirror 0.1.0) Mirror.Imports.Product.__info__/1
iex(4)> Mirror.Imports.Product.__info__(:function)
** (FunctionClauseError) no function clause matching in Mirror.Imports.Product.__info__/1

The following arguments were given to Mirror.Imports.Product.__info__/1:

    # 1
    :function

(mirror 0.1.0) Mirror.Imports.Product.__info__/1

对应的Product模块代码

defmodule Mirror.Imports.Product do
  use Ecto.Schema
  import Ecto.Changeset

  def parse_description(description) do
    {:ok, document} = Floki.parse_document(description)

    Floki.find(document, "img")
    |> Enum.map(fn {_, x,_} -> x end)
    |> Enum.map(fn [_, {"src", path}] -> path end)
    |> Enum.map(fn x -> Path.split(x) |> Enum.slice(3, 4) |> Path.join() end)
  end
end

调用Mirror.Imports.Product.__info__(:attribute)和__info__(:function)时均触发FunctionClauseError,如何配置让__info__函数正常可用?


解决方法

原因分析

use Ecto.Schema会在模块中注入自定义的__info__/1函数,这个函数只处理和Ecto Schema相关的参数(比如:schema、:source),覆盖了Elixir默认的__info__/1实现——而默认实现原本负责处理:attribute、:function这类参数,所以调用时会出现函数子句不匹配的错误。

方案一:保留默认__info__实现

在模块中手动添加对默认__info__的调用,让未被Ecto处理的参数转发给默认实现:

defmodule Mirror.Imports.Product do
  use Ecto.Schema
  import Ecto.Changeset

  # 添加该行,保留默认__info__实现
  def __info__(key), do: super(key)

  def parse_description(description) do
    {:ok, document} = Floki.parse_document(description)

    Floki.find(document, "img")
    |> Enum.map(fn {_, x,_} -> x end)
    |> Enum.map(fn [_, {"src", path}] -> path end)
    |> Enum.map(fn x -> Path.split(x) |> Enum.slice(3, 4) |> Path.join() end)
  end
end

修改后再调用__info__(:function)或__info__(:attribute)就能正常返回结果。

方案二:使用Module模块的内置函数

不需要修改模块代码,直接用Elixir标准库Module模块的函数来获取模块信息,这些函数不受自定义__info__的影响:

  • 获取模块属性:Module.attributes(Mirror.Imports.Product)
  • 获取模块函数:Module.definitions_in(Mirror.Imports.Product, :def)

内容的提问来源于stack exchange,提问作者Chen Yu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 22:56:29