Sie können nicht garantieren, dass eine Struktur gültige Werte in Elixir enthält. Ein Struct ist nur eine Map mit einem __struct__
Feld, das einen Atom enthält (normalerweise ein Modulname). Sie können jede Karte nehmen, ein __struct__
Feld hinzufügen und es wird diese Struktur.
Zum Beispiel, hier ist mir eine MapSet
Struktur ohne ein anderes Feld zu konstruieren. iex
kann nicht einmal die Struktur drucken, da die Inspect
Implementierung von MapSet
angenommen, dass es eine ist map
Schlüssel eine Karte in der Struktur enthalten:
iex(1)> %{__struct__: MapSet}
%Inspect.Error{message: "got FunctionClauseError with message \"no function clause matching in MapSet.to_list/1\" while inspecting \e[39m%{\e[0m\e[33m\e[36m__struct__: \e[0m\e[33m\e[36mMapSet\e[0m\e[33m\e[39m}\e[0m\e[33m"}
in der Regel Elixir Bibliotheken tun Was ist eine new
Funktion im Modul hinzufügen, die Argumente akzeptiert und gibt {:ok, struct}
bei einem gültigen Eingang und {:error, "description"}
(oder nur :error
) bei einem Fehler zurück. Dies verhindert nicht, dass Benutzer die Struktur mit der Syntax %ModuleName{}
erstellen. Sie können eine einfache Sicherheitsmaßnahme hinzufügen, indem Sie ein valid?
-Feld hinzufügen, das standardmäßig false
ist, und dann prüfen, ob dieser Wert in allen Ihren Funktionen wahr ist. Ecto.Changeset
verwendet eine ähnliche Technik, die Repo.insert
nicht einmal versucht, die Daten in eine Datenbank einzufügen, wenn es einen Fehler in Ecto.Changeset
gibt. Auch dies ist trivial zu umgehen.
Hier ist ein Beispiel:
defmodule MyStruct do
defstruct [:x, :y, valid?: false]
# We want `x` and `y` to always be integers.
def new(x, y) when is_integer(x) and is_integer(y) do
{:ok, %__MODULE__{x: x, y: y, valid?: true}}
end
def new(_, _), do: :error
def print(%__MODULE__{x: x, y: y, valid?: true}) do
IO.inspect {x, y}
end
end
defmodule Main do
def main do
IO.inspect MyStruct.new(1, 2)
IO.inspect MyStruct.new(1, 2.3)
{:ok, a} = MyStruct.new(1, 2)
MyStruct.print(a)
try do
# This will throw an error because `valid?` will be false.
MyStruct.print(%MyStruct{})
rescue
e -> IO.inspect e
end
# This however will work and there's no way to stop it.
MyStruct.print(%MyStruct{x: "x", y: "y", valid?: true})
end
end
Main.main
Ausgang:
{:ok, %MyStruct{valid?: true, x: 1, y: 2}}
:error
{1, 2}
%FunctionClauseError{arity: 1, function: :print, module: MyStruct}
{"x", "y"}
Sie wollen dieser Rückruf automatisch aufgerufen wird, wenn ein Benutzer des '% Some verwendet {foo: bar}' Syntax, um eine Struktur zu schaffen, ? – Dogbert
@Dogbert Ja, genau. – iTollu
Vielleicht würde es aber ausreichen, einen solchen Rückruf für den Client-Code verfügbar zu machen, falls er sich selbst überprüfen möchte. Und dann den Rückruf während der weiteren Verarbeitung aufrufen. Ich weiß immer noch nicht, was der beste Weg ist, um einen solchen Integritätscheck in Elixir zu machen. Von Scala Hintergrund kommen. – iTollu