0

我有以下代码:

defmodule Foo do
  @moduledoc false

  use Ecto.Schema

  import Ecto.Changeset


  @type t :: %__MODULE__{
          id: integer(),
          foo: String.t(),
          baz_id: String.t(),
          bar: String.t() | nil
        }

  embedded_schema do
    field :foo, :string
    field :bar, :string
  end

  @spec changeset(t() | Ecto.Changeset.t(), map()) :: Ecto.Changeset.t()
  def changeset(bae \\ %__MODULE__{}, attrs) do
    bae
    |> cast(attrs, @fields)
    |> unique_constraint(:baz_id)
  end
end

foo根据定义,baz_id不应该是。但是,正在抱怨(使用给定的),因为默认值会将它们设置为.nil@typedialyzer@spec%__MODULE__{}nil

如果我将@type定义替换为:

...
  @type t :: %__MODULE__{
          id: integer() | nil,
          foo: String.t() | nil,
          baz_id: String.t() | nil,
          bar: String.t() | nil
        }
...

那么dialyzer不会抱怨,但我不再认为某些字段不可为空。

什么是一种优雅的方式来使changeset()工作以目前的方式工作,并避免dialyzer抱怨这种特定的用途?

4

1 回答 1

2

好吧,您明确指定了违反透析器合同的默认参数(架构是下面没有默认值的裸结构),这就是透析器抱怨的原因。

%__MODULE__{}目前尚不清楚,一旦不允许,您应该如何处理空,但回答所述问题,解决方法是接受nil参数作为默认值。

@spec changeset(
    nil | t() | Ecto.Changeset.t(), map()
  ) :: Ecto.Changeset.t()
def changeset(bae \\ nil, attrs) do
  bae
  |> Kernel.||(%__MODULE__{})
  |> cast(attrs, @fields)
  |> unique_constraint(:baz_id)
end
于 2021-02-16T13:09:38.167 回答