我有以下代码:
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
根据@type
的定义,foo
和baz_id
不应该是nil
。然而,dialyzer
抱怨(与给定的@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
抱怨这个特定的使用,这将是一个优雅的方法吗?
你显式地指定了违反透析器契约的默认参数(模式是一个没有默认值的裸结构体),这就是透析器抱怨的原因。
现在还不清楚,你应该如何处理一个空的%__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