`changeset()` 规范需要逻辑上不可为空的可空类型
`changeset()` spec requires nullable type which is not logically nullable
我有以下代码:
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
我有以下代码:
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