Laufzeitarten: Tiefer im Kaninchenbau

Als ich anfing, den Hinweis " Typen, bei denen sie nicht erwartet wurden " zu schreiben , schien es mir, als hÀtte ich es geschafft, Erlang-Typen zur Laufzeit zu bringen, und jetzt kann ich sie im Client-Code auf dem Elixier verwenden. Haha, wie naiv ich war.



Alles, was durch den Link vorgeschlagen wird, funktioniert fĂŒr explizite Typdefinitionen von Verwendungsorten wie use Foo, var: type(). Leider ist dieser Ansatz zum Scheitern verurteilt, wenn wir Typen woanders definieren wollen: daneben im Code mit Modulattributen oder dort in der Konfiguration. Um beispielsweise eine Struktur zu definieren, möchten wir möglicherweise Folgendes schreiben:



# @fields [foo: 42]
# defstruct @fields

@definition var: atom()
use Foo, @definition


Leuchtturm in Französisch Katalonien



Der obige Code ist nicht so, dass er den Typ nicht so behandelt, wie wir es wollen - er wird ĂŒberhaupt nicht erfasst, weil er @definition var: atom()eine Ausnahme auslöst ** (CompileError) undefined function atom/0.



Naiver Ansatz



 â€” « » ( @tsilb, , .) , , , , â€” .



, , __using__/1: , ( field → type()),  â€” , , , {Module, :type, [params]}. ~q||, , , , AST. quote/1 : foo: ~q|atom()|. , , . . , - , , , , . , , - - - , .



. , erlang  â€”  , , .  â€” , , ( ).



, . , , , , , , â€”  . , .



Tyyppi



,  â€” , XY . , , —   â€” . Tyyppi.



Code.Typespec, . : . , , , . , , .  â€”  Tyyppi.of?/2, ,  â€” «»/«» , .



iex|tyyppi|1  Tyyppi.of? GenServer.on_start(), {:ok, self()}
#⇒ true
iex|tyyppi|2  Tyyppi.of? GenServer.on_start(), :ok
#⇒ false


- , Tyyppi.T. Tyyppi.of?/2 - â€” Tyyppi.of_type?/2.



iex|tyyppi|3  type = Tyyppi.parse(GenServer.on_start)
iex|tyyppi|4  Tyyppi.of_type? type, {:ok, self()}
#⇒ true


, , , , , . :erlang.term_to_binary/1, Config.Provider.





, : . , . , key: type(). Access, upserts. , Ecto.Changeset cast_field/1 validate/1.



, , , , ( , ).



defmodule MyStruct do
  import Kernel, except: [defstruct: 1]
  import Tyyppi.Struct, only: [defstruct: 1]

  @typedoc "The user type defined before `defstruct/1` declaration"
  @type my_type :: :ok | {:error, term()}

  @defaults foo: :default,
            bar: :erlang.list_to_pid('<0.0.0>'),
            baz: {:error, :reason}
  defstruct foo: atom(), bar: GenServer.on_start(), baz: my_type()

  def cast_foo(atom) when is_atom(atom), do: atom
  def cast_foo(binary) when is_binary(binary),
    do: String.to_atom(binary)

  def validate(%{foo: :default} = my_struct), do: {:ok, my_struct}
  def validate(%{foo: foo} = my_struct), do: {:error, {:foo, foo}
end


Ich habe keine Ahnung, welchen praktischen Wert diese Bibliothek in der Produktion hat (LĂŒge, ich weiß: keine), aber sie kann sicherlich ein großer Helfer wĂ€hrend der Entwicklung sein, der es Ihnen ermöglicht, Ihre Suche einzugrenzen und seltsame Fehler zu isolieren, die mit der Dynamik von Typen in Elixir verbunden sind vor allem im Umgang mit externen Quellen.



Der gesamte Bibliothekscode ist wie immer auf dem Github verfĂŒgbar .






Viel Spaß beim Tippen zur Laufzeit!




All Articles