官术网_书友最值得收藏!

Structs

Structs are an abstraction built on top of maps. We define a struct inside a module, with the defstruct construct. The struct's name is the name of the module it's being defined in (which means you can only define one struct per module). To defstruct, we pass a keyword list, which contains the key-value pairs that define the fields that struct has, along with their default values. Let's define a Folder struct:

$ cat examples/folder.ex
defmodule Folder do
defstruct name: "new folder", files_info: [], path: nil
end

We can now use it in our IEx session:

iex> %Folder{}
%Folder{files_info: [], name: "new folder", path: nil}
iex> %Folder{}.name
"new folder"
iex> %Folder{}.files_info
[]

Elixir already has a File module, which provides several functions to deal with files. One of them is the File.stat/2, which returns a %File.Stat{} struct with information about the provided path. The files_info field in our %Folder{} struct is a list, which will contain %File.Stat{} structs as elements. Let's initialize a folder with one file:

iex> folder = %Folder{files_info: [File.stat!("string_helper.ex")]}
%Folder{files_info: [%File.Stat{access: :read_write,
atime: {{2017, 12, 31}, {16, 58, 56}}, ctime: {{2017, 12, 30}, {3, 40, 29}},
gid: 100, inode: 3290229, links: 1, major_device: 65024, minor_device: 0,
mode: 33188, mtime: {{2017, 12, 30}, {3, 40, 29}}, size: 509, type: :regular,
uid: 1000}], name: "new folder", path: nil}

Note that this example assumes you have a "string_helper.ex" file in the directory where you started iex. Also note that we're using File.stat!, which works similarly to File.stat, but, instead of returning a {:ok, result} tuple, it returns the result itself.

We now have our %Folder{} struct with one file. We can now show you the syntax to update a struct, which is similar to the one used in maps (or you can use the functions from the Map module). Assuming you also have a "recursion.ex" file on your current working directory, you can use this syntax to update the struct:

iex> folder = %Folder{ folder | files_info: [File.stat!("recursion.ex") | folder.files_info]}
%Folder{files_info: [%File.Stat{access: :read_write,
atime: {{2017, 12, 30}, {20, 8, 29}}, ctime: {{2017, 12, 30}, {20, 8, 25}},
gid: 100, inode: 3278529, links: 1, major_device: 65024, minor_device: 0,
mode: 33188, mtime: {{2017, 12, 30}, {20, 8, 25}}, size: 270, type: :regular,
uid: 1000},
%File.Stat{access: :read_write, atime: {{2017, 12, 31}, {16, 58, 56}},
ctime: {{2017, 12, 30}, {3, 40, 29}}, gid: 100, inode: 3290229, links: 1,
major_device: 65024, minor_device: 0, mode: 33188,
mtime: {{2017, 12, 30}, {3, 40, 29}}, size: 509, type: :regular, uid: 1000}],
name: "new folder", path: nil}
iex> folder.files_info
[%File.Stat{access: :read_write, atime: {{2017, 12, 30}, {20, 8, 29}},
ctime: {{2017, 12, 30}, {20, 8, 25}}, gid: 100, inode: 3278529, links: 1,
major_device: 65024, minor_device: 0, mode: 33188,
mtime: {{2017, 12, 30}, {20, 8, 25}}, size: 270, type: :regular, uid: 1000},
%File.Stat{access: :read_write, atime: {{2017, 12, 31}, {16, 58, 56}},
ctime: {{2017, 12, 30}, {3, 40, 29}}, gid: 100, inode: 3290229, links: 1,
major_device: 65024, minor_device: 0, mode: 33188,
mtime: {{2017, 12, 30}, {3, 40, 29}}, size: 509, type: :regular, uid: 1000}]

As you can see, we now have two files in our %Folder{} struct.

Although structs are implemented on top of maps, they do not share protocol implementations with the Map module. This means that you can't, out of the box, iterate on a struct, as it doesn't implement the Enumerable protocol.

We'll end our little tour of structs with two more bits of information. First, if you don't provide a default value when defining the fields of a struct, nil will be assumed as its default value. Second, you can enforce that certain fields are required when creating your struct. You do that with the @enforce_keys module attribute. If we wanted to make sure path was provided when creating our %Folder{} struct, we would define it as following:

$ cat examples/folder_with_enforce_keys.ex
defmodule Folder do
@enforce_keys :path

defstruct name: "new folder", files_info: [], path: nil
end

If you don't provide path when creating this struct, ArgumentError will be raised:

iex> %Folder{}
** (ArgumentError) the following keys must also be given when building struct Folder: [:path]
expanding struct: Folder.__struct__/1
iex:46: (file)
iex> %Folder{path: "/a/b/c/"}
%Folder{files_info: [], name: "new folder", path: "/a/b/c/"}
主站蜘蛛池模板: 枞阳县| 罗甸县| 石屏县| 柳林县| 利津县| 张北县| 勃利县| 浦江县| 鹿邑县| 镇坪县| 乌鲁木齐市| 肥西县| 芦山县| 安康市| 平阴县| 陵水| 侯马市| 迁安市| 海晏县| 沅江市| 静海县| 大港区| 潞西市| 广水市| 乌海市| 宁晋县| 山西省| 韶关市| 宁陕县| 页游| 上思县| 普格县| 翁牛特旗| 潜江市| 朝阳区| 珲春市| 望江县| 商水县| 诏安县| 通道| 万安县|