I would like to define a number of structs
in a module. From what I have read, structs defined with defstruct
seems to define a struct that takes the name of the enclosing module. Is there another way to do this?
There is no other way to define structs
in Elixir.
The Kernel.defstruct
macro automatically uses the calling module’s name and only allows for one struct per module:
One alternative to structs (though less common in Elixir) would be Erlang’s Records which are available in Elixir through the Record
module. This also allows you to create multiple different record types per module. You can learn more about records in the documentation of the Record module.
You can do something like this:
defmodule Foo do
defmodule Bar do
defstruct ...
end
defmodule Baz do
defstruct ...
end
end
Thanks! I’ll look into it.
Thanks! I’ll take a look.
If you’re willing to change your struct syntax slightly you could use my TypeStruct package.
Usage is as follows:
defmodule Foo do
use TypeStruct
defstruct User,
id: integer,
name: String.t \\ "",
eye_color: :black | :blue | :brown | :green
defstruct Group,
id: integer,
name: String.t,
users: [User.t] \\ []
end
After the key comes the type for the field. Default values can be specified with \\ <default value>
(Above, the struct Foo.User
defines a field :name
with a default value of ""
, and the struct Foo.Group
defines a field :users
with a default value of []
.) Note that fields without a default value are required when creating a struct (in vanilla Elixir they default to nil
instead), so if you want a field to default to nil
you must explicitly declare field: String.t | nil \\ nil
.
Types for the structs are automatically defined (that’s the whole point of the library). The default type is a normal type t
. You can set the type with the syntax defstruct Foo, opaque(bar), x: integer
. (I am considering changing the default type to opaque.)
(There’s unfortunately no documentation for the library, but that should be all you need for your purpose. I’ve been meaning to document the library for a while.)
Alternatively, you could define your own macro for defining nested structs:
defmodule NestedStruct do
defmacro defstruct(alias, fields) do
quote do
defmodule unquote(alias), do: defstruct unquote(fields)
end
end
end
defmodule Foo do
import NestedStruct
defstruct Bar,
a: nil,
b: nil
end
Hey, this looks great! I will try it out. Thanks for the post!!
Ooo that looks quite nice. Is it still possible to use it in an enclosing module to put functions on it, or does it have its own do
/end
block for adding functions?
Yes, you can use it without defining a new module!
defmodule User do
use TypeStruct
defstruct id: integer,
name: String.t
end
OK! This is looking very good!!
For anyone stumbling on this thread, have a look at the typedstruct
package instead of TypeStruct
.