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

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/"}
主站蜘蛛池模板: 余姚市| 珲春市| 兰州市| 新河县| 大关县| 辽阳市| 灵川县| 阿合奇县| 济源市| 镇安县| 崇明县| 桃园市| 苏尼特左旗| 慈利县| 体育| 五大连池市| 东兰县| 阿瓦提县| 庄河市| 通山县| 日喀则市| 酉阳| 白城市| 平度市| 得荣县| 绥江县| 雷山县| 景泰县| 马龙县| 绵阳市| 鹿泉市| 苗栗县| 安西县| 武城县| 三门县| 浑源县| 琼海市| 德化县| 海晏县| 建始县| 大安市|