<?xml version="1.0" encoding="utf-8"?>

<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
	<channel>
		<title>Форум программистов и сисадминов Киберфорум - Блоги - loothood</title>
		<link>https://www.cyberforum.ru/blogs/606805/</link>
		<description>КиберФорум - форум программистов, системных администраторов, администраторов баз данных, компьютерный форум, форум по электронике и бытовой технике, обсуждение софта. Бесплатная помощь в решении задач по программированию и наукам, решение проблем с компьютером, операционными системам</description>
		<language>ru</language>
		<lastBuildDate>Sun, 06 Sep 2026 08:03:58 GMT</lastBuildDate>
		<generator>vBulletin</generator>
		<ttl>60</ttl>
		<image>
			<url>https://www.cyberforum.ru//cyberstatic.net/images/misc/rss.jpg</url>
			<title>Форум программистов и сисадминов Киберфорум - Блоги - loothood</title>
			<link>https://www.cyberforum.ru/blogs/606805/</link>
		</image>
		<item>
			<title>Сайт на Rust с использованием фреймворка Rocket</title>
			<link>https://www.cyberforum.ru/blogs/606805/5421.html</link>
			<pubDate>Mon, 19 Nov 2018 12:30:32 GMT</pubDate>
			<description>Всем привет.  
 
 
 
О чем 
 
У меня давно была задумка.  
Сделать шутливый сайт для друзей. Все...</description>
			<content:encoded><![CDATA[<div>Всем привет. <br />
<br />
<br />
<br />
<font size="3">О чем<br />
</font><br />
У меня давно была задумка. <br />
Сделать шутливый сайт для друзей. Все что этот сайт делает - для друга генерирует случайное прилагательное. Эта генерация сохраняется в базу. На сайте можно глянуть топ-10 сочетаний. Так же, по клику на друга или прилагательное, можно будет глянуть топ-10 сочетаний для этого прилагательного или друга.<br />
Звучит очень просто. Потому это отличная задачка для изучения новых технологий. Я какое-то время уже пишу на <a rel="nofollow noopener noreferrer" href="https://www.rust-lang.org/ru-RU/" target="_blank" title="https://www.rust-lang.org/ru-RU/">rust</a> в свободное от работы время - просто для изучения новых технологий и развлечения.<br />
Но гуру Rust я не являюсь.<br />
Так же, я довольно далек от веба, потому эту часть тоже пришлось учить.<br />
Эту статью я пишу как продолжение обучения. Чтобы для себя разложить все по полочкам.<br />
Если она кому-то чем-то поможет, буду только рад.<br />
Чтож, цель есть, время выбрать фреймворк.<br />
<br />
<br />
<br />
<font size="3">Фреймворк</font><br />
Сейчас для Rust есть около десятка веб-фреймворков, это <a rel="nofollow noopener noreferrer" href="https://github.com/iron/iron" target="_blank" title="https://github.com/iron/iron">Iron</a>, <a rel="nofollow noopener noreferrer" href="https://github.com/carllerche/tower-web" target="_blank" title="https://github.com/carllerche/tower-web">Tower Web</a>, <a rel="nofollow noopener noreferrer" href="https://gotham.rs" target="_blank" title="https://gotham.rs">Gotham</a>, <a rel="nofollow noopener noreferrer" href="https://rocket.rs" target="_blank" title="https://rocket.rs">Rocket</a> и другие. Вообще, вы можете посмотреть на <a rel="nofollow noopener noreferrer" href="http://arewewebyet.org" target="_blank" title="http://arewewebyet.org">arewewebyet.org</a> какую инфраструктуру rust предлагает на данный момент для веба.<br />
Критерии для фреймворка были простые: <br />
1) коммиты в репозитрии чем свежее тем лучше.<br />
2) примеры, которые указаны на сайте/в репозитории, работают без лишних приседаний.<br />
3) если сообщество, которое ипользует этот фреймворк, большое, то это очевидный плюс.<br />
Чтож, почти все фреймворки проходили по пункту 1. Переходим к пункту 2.<br />
К сожалению, или я криворукий, или примеры старые, но без приседаний, мне удалось завести примеры только для <a rel="nofollow noopener noreferrer" href="https://github.com/iron/iron" target="_blank" title="https://github.com/iron/iron">Iron</a> и <a rel="nofollow noopener noreferrer" href="https://github.com/carllerche/tower-web" target="_blank" title="https://github.com/carllerche/tower-web">Tower Web</a>. Так же, мне удалось завести пример для <a rel="nofollow noopener noreferrer" href="https://rocket.rs" target="_blank" title="https://rocket.rs">Rocket</a>, но пришлось указать ночную сборку rust. <br />
Третий этап оказался простым - <a rel="nofollow noopener noreferrer" href="https://rocket.rs" target="_blank" title="https://rocket.rs">Rocket</a> гораздо больше распространен чем <a rel="nofollow noopener noreferrer" href="https://github.com/iron/iron" target="_blank" title="https://github.com/iron/iron">Iron</a> и <a rel="nofollow noopener noreferrer" href="https://github.com/carllerche/tower-web" target="_blank" title="https://github.com/carllerche/tower-web">Tower Web</a>. У него отличная документация. Потому выбор был очевиден. <br />
<br />
<br />
<br />
<font size="3">Архитектура</font><br />
По моему личному мнению, для любого проекта, даже такого маленького, продумать архитектуру заранее - хорошая идея.<br />
Начнем с базы. <br />
У нас будет три таблицы: таблица с друзьями(я назвал ее active-user), таблица с прилагательными(adjective), таблица с сочетаниями друг-прилагательное(user_adjective). Схему можно нарисовать <br />
Дальше - архитектура кода.<br />
Так как мы учимся, нет никаких ограничений, я решил сделать все по-взрослому: работа с базой через ORM. Несколько слоев проекта - бэкенд, миддл, фронтенд.<br />
Максимальное разделение по логике (поможет при росте проекта). В общем, дерево проекта выглядит так:<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="397495811"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="397495811" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
</pre></td><td class="de1"><pre class="de1">$ <span class="kw2">tree</span> <span class="re5">-L</span> <span class="nu0">10</span> <span class="re5">-I</span> target
.
<span class="sy0">|</span>--- Cargo.lock
<span class="sy0">|</span>--- Cargo.toml
<span class="sy0">|</span>--- Rocket.toml
<span class="sy0">|</span>--- migrations
<span class="sy0">|**</span> <span class="sy0">|</span>--- 00000000000000_diesel_initial_setup
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- down.sql
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- up.sql
<span class="sy0">|**</span> <span class="sy0">|</span>--- <span class="nu0">2018</span>-08-<span class="nu0">15</span>-<span class="nu0">131959</span>_create_user
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- down.sql
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- up.sql
<span class="sy0">|**</span> <span class="sy0">|</span>--- <span class="nu0">2018</span>-08-<span class="nu0">15</span>-<span class="nu0">132408</span>_create_adjective
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- down.sql
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- up.sql
<span class="sy0">|**</span> <span class="sy0">|</span>--- <span class="nu0">2018</span>-08-<span class="nu0">15</span>-<span class="nu0">132416</span>_create_user_adjective
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- down.sql
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- up.sql
<span class="sy0">|**</span> <span class="sy0">|</span>--- <span class="nu0">2018</span>-08-<span class="nu0">15</span>-<span class="nu0">132833</span>_fill_user
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- down.sql
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- up.sql
<span class="sy0">|**</span> <span class="sy0">|</span>--- <span class="nu0">2018</span>-08-<span class="nu0">15</span>-<span class="nu0">132837</span>_fill_adjective
<span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- down.sql
<span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- up.sql
<span class="sy0">|</span>--- src
<span class="sy0">|**</span> <span class="sy0">|</span>--- backend
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- handler.rs
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- mod.rs
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- routes.rs
<span class="sy0">|**</span> <span class="sy0">|</span>--- database
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- connection.rs
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- dbimpl.rs
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- mod.rs
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- models
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- adjective.rs
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- mod.rs
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- user.rs
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- user_adjective.rs
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- schema.rs
<span class="sy0">|**</span> <span class="sy0">|</span>--- main.rs
<span class="sy0">|**</span> <span class="sy0">|</span>--- middleware
<span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- display_data.rs
<span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- mod.rs
<span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- randomize.rs
<span class="sy0">|</span>--- static
<span class="sy0">|**</span> <span class="sy0">|</span>--- generate.js
<span class="sy0">|**</span> <span class="sy0">|</span>--- img
<span class="sy0">|**</span> <span class="sy0">|**</span> <span class="sy0">|</span>--- logo.jpg
<span class="sy0">|**</span> <span class="sy0">|</span>--- spectre
<span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- bootstrap-theme.css
<span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- bootstrap-theme.css.map
<span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- bootstrap-theme.min.css
<span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- bootstrap-theme.min.css.map
<span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- bootstrap.css
<span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- bootstrap.css.map
<span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- bootstrap.min.css
<span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- bootstrap.min.css.map
<span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- spectre-exp.css
<span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- spectre-exp.min.css
<span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- spectre-icons.css
<span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- spectre-icons.min.css
<span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- spectre.css
<span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- spectre.min.css
<span class="sy0">|</span>--- templates
&nbsp; &nbsp; <span class="sy0">|</span>--- adjective.html.hbs
&nbsp; &nbsp; <span class="sy0">|</span>--- common
&nbsp; &nbsp; <span class="sy0">|**</span> <span class="sy0">|</span>--- footer.hbs
&nbsp; &nbsp; <span class="sy0">|**</span> <span class="sy0">|</span>--- meta
&nbsp; &nbsp; <span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- footer.hbs
&nbsp; &nbsp; <span class="sy0">|**</span> &nbsp; &nbsp; <span class="sy0">|</span>--- header.hbs
&nbsp; &nbsp; <span class="sy0">|</span>--- error
&nbsp; &nbsp; <span class="sy0">|**</span> <span class="sy0">|</span>--- <span class="nu0">404</span>.html.hbs
&nbsp; &nbsp; <span class="sy0">|</span>--- index.html.hbs
&nbsp; &nbsp; <span class="sy0">|</span>--- user.html.hbs
&nbsp;
<span class="nu0">19</span> directories, <span class="nu0">55</span> files</pre></td></tr></table></div></td></tr></tbody></table></div><br />
<br />
<font size="3">Первые шаги</font><br />
Честно говоря, описывать первые шаги - довольно скучное занятие, которое описано уже в тысячах туториалах. <br />
Как установить rust, написано на сайте <a rel="nofollow noopener noreferrer" href="https://www.rust-lang.org/ru-RU/" target="_blank" title="https://www.rust-lang.org/ru-RU/">rust</a><br />
Надо создать проект. Я использую Intellij IDEA с плагином, потому создание нового проекта - дело трех кликов и выбора имени проекта.<br />
Вы же можете воспользоваться такой командой:<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="458848607"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="458848607" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">cargo new hello_world <span class="re5">--bin</span></pre></td></tr></table></div></td></tr></tbody></table></div><b>--bin</b> значит что мы создаем не библиотеку(то есть, будет файлик с именем main.rs). Подробнее в <a rel="nofollow noopener noreferrer" href="https://doc.rust-lang.org/cargo/guide/creating-a-new-project.html" target="_blank" title="https://doc.rust-lang.org/cargo/guide/creating-a-new-project.html">документации</a>.<br />
<br />
<br />
<br />
<font size="3">Работа с базой</font><br />
Я давно работаю с PostgreSQL, потому вопрос какую БД использовать не возникал.<br />
Тем более, есть замечательная ORM библиотека(в rust мире библиотеки называют крэйтами(crates)) <a rel="nofollow noopener noreferrer" href="https://diesel.rs" target="_blank" title="https://diesel.rs">diesel</a>. С ее помощью можно работать с PostgreSQL. <br />
Хорошим тоном считается работа с базой через пулы(pools). Потому, я выбрал связку <a rel="nofollow noopener noreferrer" href="https://github.com/sfackler/r2d2" target="_blank" title="https://github.com/sfackler/r2d2">r2d2</a>+<a rel="nofollow noopener noreferrer" href="https://diesel.rs" target="_blank" title="https://diesel.rs">diesel</a>.<br />
Первым делом, надо в проект подключить крэйты. Потому в Cargo.toml мы пишем:<br />
<div class="codeblock"><table class="json"><thead><tr><td colspan="2" id="199876947"  class="head">JSON</td></tr></thead><tbody><tr class="li1"><td><div id="199876947" style="height: 94px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#91;</span>dependencies<span class="br0">&#93;</span>
diesel <span class="sy0">=</span> &nbsp;<span class="br0">&#123;</span> version <span class="sy0">=</span> <span class="st0">&quot;1.3.2&quot;</span><span class="sy0">,</span> features <span class="sy0">=</span> <span class="br0">&#91;</span><span class="st0">&quot;postgres&quot;</span><span class="br0">&#93;</span> <span class="br0">&#125;</span>
r2d2 <span class="sy0">=</span> <span class="st0">&quot;0.8.2&quot;</span>
r2d2<span class="sy0">-</span>diesel <span class="sy0">=</span> <span class="st0">&quot;1.0.0&quot;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Текущие версии крэйтов можно посмотреть на <a rel="nofollow noopener noreferrer" href="http://crates.io" target="_blank" title="http://crates.io">crates.io</a><br />
Прежде чем продолжить работу, установим тулу под названием diesel_cli:<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="751542721"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="751542721" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">cargo <span class="kw2">install</span> diesel_cli</pre></td></tr></table></div></td></tr></tbody></table></div>Далее, надо инициализировать базу. Делается это просто: в файл <b>.env</b> в переменной <b>DATABASE_URL</b>, указываем как коннектиться к базе. Выглядит это примено так:<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="139420107"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="139420107" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1"><span class="re2">DATABASE_URL</span>=postgres:<span class="sy0">//</span>mylogin:mypassword<span class="sy0">@</span>myhost<span class="sy0">/</span>mydb</pre></td></tr></table></div></td></tr></tbody></table></div>В консоли пишем <br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="697673050"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="697673050" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">diesel setup</pre></td></tr></table></div></td></tr></tbody></table></div>База создана, можно создавать миграции. Делается это тоже из консоли. Подробней о миграциях и как работать с <a rel="nofollow noopener noreferrer" href="https://diesel.rs" target="_blank" title="https://diesel.rs">diesel</a>, можно прочитать <a rel="nofollow noopener noreferrer" href="http://diesel.rs/guides/getting-started/" target="_blank" title="http://diesel.rs/guides/getting-started/">тут</a>.<br />
После выполнения миграций, которые создадут таблицы, надо создать схему базы, чтобы наш проект знал как работать с базой. Схему можно сделать руками. Но проще воспользоваться diesel_cli:<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="960688080"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="960688080" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">diesel print-schema <span class="sy0">&gt;</span> src<span class="sy0">/</span>schema.rs</pre></td></tr></table></div></td></tr></tbody></table></div>У вас будет файлик примерно такого содержания:<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="502118488"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="502118488" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="de1"><pre class="de1">table<span class="sy0">!</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; active_user <span class="br0">&#40;</span><span class="kw3">id</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">id</span> <span class="sy0">-&gt;</span> Int4,
&nbsp; &nbsp; &nbsp; &nbsp; user_name <span class="sy0">-&gt;</span> Varchar,
&nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
table<span class="sy0">!</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; adjective <span class="br0">&#40;</span><span class="kw3">id</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">id</span> <span class="sy0">-&gt;</span> Int4,
&nbsp; &nbsp; &nbsp; &nbsp; adjective_value <span class="sy0">-&gt;</span> Varchar,
&nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
table<span class="sy0">!</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; user_adjective <span class="br0">&#40;</span><span class="kw3">id</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">id</span> <span class="sy0">-&gt;</span> Int4,
&nbsp; &nbsp; &nbsp; &nbsp; user_id <span class="sy0">-&gt;</span> Int4,
&nbsp; &nbsp; &nbsp; &nbsp; adjective_id <span class="sy0">-&gt;</span> Int4,
&nbsp; &nbsp; &nbsp; &nbsp; count <span class="sy0">-&gt;</span> Nullable<span class="sy0">&lt;</span>Int4<span class="sy0">&gt;</span>,
&nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
allow_tables_to_appear_in_same_query<span class="sy0">!</span><span class="br0">&#40;</span>
&nbsp; &nbsp; active_user,
&nbsp; &nbsp; adjective,
&nbsp; &nbsp; user_adjective,
<span class="br0">&#41;</span>;</pre></td></tr></table></div></td></tr></tbody></table></div>Все! Можно программировать на Rust!<br />
Перво-наперво, давайте создадим Модели. В терминах diesel, модель - это описание таблицы, с которой мы будем работать. Моя модель таблицы user:<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="515175711"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="515175711" style="height: 110px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
</pre></td><td class="de1"><pre class="de1"><span class="sy0">#</span><span class="br0">&#91;</span>derive<span class="br0">&#40;</span>Clone, Queryable, Serialize, Deserialize, FromForm<span class="br0">&#41;</span><span class="br0">&#93;</span>
pub struct User <span class="br0">&#123;</span>
&nbsp; &nbsp; pub <span class="kw3">id</span> <span class="sy0">:</span> i32,
&nbsp; &nbsp; pub user_name <span class="sy0">:</span> <span class="kw4">String</span>,
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Тут все очевидно, кроме, наверное, первой строчки <br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="192080959"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="192080959" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1"><span class="sy0">#</span><span class="br0">&#91;</span>derive<span class="br0">&#40;</span>Clone, Queryable, Serialize, Deserialize, FromForm<span class="br0">&#41;</span><span class="br0">&#93;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Здесь мы применяем очень мощную штуку. Называется она макрос. Если быть точным, то процедурный макрос. Используются эти макросы в основном для кодогенерации. Работает это так: у нас есть тип данных i32. Для него уже описан ряд методов и типажей. Мы создаем структуру, внутри которой есть данные типа i32. И тут мы захотели эту структуру клонировать (вызвать для этой структуры метод clone()). Чтобы не писать этот метод специально для этой структуры, мы убеждаемся что для всех типов данных внутри этой структуры уже написан метод clone. и просто заимствуем (derive) существующий метод. Так как у меня в структуре данные типа i32 и String, для которых уже реализован типаж Clone, внутри которого есть метод clone, все что мне надо сделать - это заимствовать типаж Clone. <br />
<br />
Вот код, который демонстрирует как создать коннект к базе:<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="90362404"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="90362404" style="height: 286px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="de1"><pre class="de1">use diesel<span class="sy0">::</span>pg<span class="sy0">::</span>PgConnection;
use r2d2;
use r2d2_diesel<span class="sy0">::</span>ConnectionManager;
use std<span class="sy0">::</span>env;
&nbsp;
<span class="kw1">type</span> Pool <span class="sy0">=</span> r2d2<span class="sy0">::</span>Pool<span class="sy0">&lt;</span>ConnectionManager<span class="sy0">&lt;</span>PgConnection<span class="sy0">&gt;&gt;</span>;
&nbsp;
pub fn init_pool<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">-&gt;</span> Pool <span class="br0">&#123;</span>
&nbsp; &nbsp; dotenv<span class="br0">&#40;</span><span class="br0">&#41;</span>.ok<span class="br0">&#40;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="kw1">let</span> manager <span class="sy0">=</span> ConnectionManager<span class="sy0">::&lt;</span>PgConnection<span class="sy0">&gt;::</span>new<span class="br0">&#40;</span>database_url<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; Pool<span class="sy0">::</span>new<span class="br0">&#40;</span>manager<span class="br0">&#41;</span>.expect<span class="br0">&#40;</span><span class="st0">&quot;Cannot initialize db pool&quot;</span><span class="br0">&#41;</span>
<span class="br0">&#125;</span>
&nbsp;
fn database_url<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">-&gt;</span> <span class="kw4">String</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; env<span class="sy0">::</span>var<span class="br0">&#40;</span><span class="st0">&quot;DATABASE_URL&quot;</span><span class="br0">&#41;</span>.expect<span class="br0">&#40;</span><span class="st0">&quot;DATABASE_URL must be set&quot;</span><span class="br0">&#41;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Тут тоже все довольно просто: init_pool - функция которую мы будем вызывать чтобы передать фреймворку пул для коннекта к базе с которым он будет работать. Все остальное - типы и вспомогательные функции для создания пула.<br />
<br />
Далее, нам надо как-то читать/писать/обновлять данные в базе. Я создал отдельную прослойку на среднем уровне для работы с базой:<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="481536642"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="481536642" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
</pre></td><td class="de1"><pre class="de1">use diesel;
use diesel<span class="sy0">::</span><span class="br0">&#123;</span> pg<span class="sy0">::</span>PgConnection
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , RunQueryDsl
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , prelude<span class="sy0">::*</span>
<span class="br0">&#125;</span>;
use database<span class="sy0">::</span>schema<span class="sy0">::*</span>;
use database<span class="sy0">::</span>models<span class="sy0">::</span><span class="br0">&#123;</span> user<span class="sy0">::</span>User
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , adjective<span class="sy0">::</span>Adjective
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , user_adjective<span class="sy0">::</span><span class="br0">&#123;</span> UserAdjective
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , NewUsAdRecord <span class="br0">&#125;</span>
<span class="br0">&#125;</span>;
use failure<span class="sy0">::</span>Error;
&nbsp;
pub fn all_users<span class="br0">&#40;</span>connection<span class="sy0">:</span> <span class="sy0">&amp;</span>PgConnection<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> QueryResult<span class="sy0">&lt;</span>Vec<span class="sy0">&lt;</span>User<span class="sy0">&gt;&gt;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; active_user<span class="sy0">::</span>table.load<span class="sy0">::&lt;</span>User<span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="sy0">&amp;*</span>connection<span class="br0">&#41;</span>
<span class="br0">&#125;</span>
&nbsp;
pub fn all_adjectives<span class="br0">&#40;</span>connection<span class="sy0">:</span> <span class="sy0">&amp;</span>PgConnection<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> QueryResult<span class="sy0">&lt;</span>Vec<span class="sy0">&lt;</span>Adjective<span class="sy0">&gt;&gt;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; adjective<span class="sy0">::</span>table.load<span class="sy0">::&lt;</span>Adjective<span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="sy0">&amp;*</span>connection<span class="br0">&#41;</span>
<span class="br0">&#125;</span>
&nbsp;
pub fn get_user_by_id<span class="br0">&#40;</span>connection <span class="sy0">:</span> <span class="sy0">&amp;</span>PgConnection, <span class="kw3">id</span> <span class="sy0">:</span> <span class="sy0">&amp;</span>i32<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> QueryResult<span class="sy0">&lt;</span>User<span class="sy0">&gt;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; active_user<span class="sy0">::</span>table
&nbsp; &nbsp; &nbsp; &nbsp; .find<span class="br0">&#40;</span><span class="kw3">id</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .get_result<span class="sy0">::&lt;</span>User<span class="sy0">&gt;</span><span class="br0">&#40;</span>connection<span class="br0">&#41;</span>
<span class="br0">&#125;</span>
&nbsp;
pub fn get_user_by_name<span class="br0">&#40;</span>connection <span class="sy0">:</span> <span class="sy0">&amp;</span>PgConnection, name <span class="sy0">:</span> <span class="sy0">&amp;</span>str<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> QueryResult<span class="sy0">&lt;</span>User<span class="sy0">&gt;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; active_user<span class="sy0">::</span>table
&nbsp; &nbsp; &nbsp; &nbsp; .<span class="kw3">filter</span><span class="br0">&#40;</span>active_user<span class="sy0">::</span>user_name.eq<span class="br0">&#40;</span>name<span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .get_result<span class="br0">&#40;</span>connection<span class="br0">&#41;</span>
<span class="br0">&#125;</span>
&nbsp;
pub fn get_adjective_by_id<span class="br0">&#40;</span>connection <span class="sy0">:</span> <span class="sy0">&amp;</span>PgConnection, <span class="kw3">id</span> <span class="sy0">:</span> <span class="sy0">&amp;</span>i32<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> QueryResult<span class="sy0">&lt;</span>Adjective<span class="sy0">&gt;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; adjective<span class="sy0">::</span>table
&nbsp; &nbsp; &nbsp; &nbsp; .find<span class="br0">&#40;</span><span class="kw3">id</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .get_result<span class="sy0">::&lt;</span>Adjective<span class="sy0">&gt;</span><span class="br0">&#40;</span>connection<span class="br0">&#41;</span>
<span class="br0">&#125;</span>
&nbsp;
pub fn get_adjective_by_name<span class="br0">&#40;</span>connection <span class="sy0">:</span> <span class="sy0">&amp;</span>PgConnection, name <span class="sy0">:</span> <span class="sy0">&amp;</span>str<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> QueryResult<span class="sy0">&lt;</span>Adjective<span class="sy0">&gt;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; adjective<span class="sy0">::</span>table
&nbsp; &nbsp; &nbsp; &nbsp; .<span class="kw3">filter</span><span class="br0">&#40;</span>adjective<span class="sy0">::</span>adjective_value.eq<span class="br0">&#40;</span>name<span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .get_result<span class="br0">&#40;</span>connection<span class="br0">&#41;</span>
<span class="br0">&#125;</span>
&nbsp;
pub fn get_top10_all<span class="br0">&#40;</span>conn <span class="sy0">:</span> <span class="sy0">&amp;</span>PgConnection<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> Result<span class="sy0">&lt;</span>Vec<span class="sy0">&lt;</span>UserAdjective<span class="sy0">&gt;</span>, Error<span class="sy0">&gt;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">let</span> query <span class="sy0">=</span> user_adjective<span class="sy0">::</span>table
&nbsp; &nbsp; &nbsp; &nbsp; .order<span class="br0">&#40;</span>user_adjective<span class="sy0">::</span>user_id<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .order<span class="br0">&#40;</span>user_adjective<span class="sy0">::</span>count.desc<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .limit<span class="br0">&#40;</span><span class="nu0">10</span><span class="br0">&#41;</span>;
&nbsp;
&nbsp; &nbsp; <span class="kw1">let</span> us_adj <span class="sy0">=</span> query.load<span class="sy0">::&lt;</span>UserAdjective<span class="sy0">&gt;</span><span class="br0">&#40;</span>conn<span class="br0">&#41;</span><span class="sy0">?</span>;
&nbsp;
&nbsp; &nbsp; Ok<span class="br0">&#40;</span>us_adj<span class="br0">&#41;</span>
<span class="br0">&#125;</span>
&nbsp;
pub fn get_count_of_repeats<span class="br0">&#40;</span>conn <span class="sy0">:</span> <span class="sy0">&amp;</span>PgConnection, user_id <span class="sy0">:</span> <span class="sy0">&amp;</span>i32, adjective_id <span class="sy0">:</span> <span class="sy0">&amp;</span>i32<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> Result<span class="sy0">&lt;</span>Vec<span class="sy0">&lt;</span>UserAdjective<span class="sy0">&gt;</span>, Error<span class="sy0">&gt;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">let</span> query <span class="sy0">=</span> user_adjective<span class="sy0">::</span>table
&nbsp; &nbsp; &nbsp; &nbsp; .<span class="kw3">filter</span><span class="br0">&#40;</span>user_adjective<span class="sy0">::</span>user_id.eq<span class="br0">&#40;</span>user_id<span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .<span class="kw3">filter</span><span class="br0">&#40;</span>user_adjective<span class="sy0">::</span>adjective_id.eq<span class="br0">&#40;</span>adjective_id<span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp;
&nbsp; &nbsp; <span class="kw1">let</span> us_adj <span class="sy0">=</span> query.load<span class="sy0">::&lt;</span>UserAdjective<span class="sy0">&gt;</span><span class="br0">&#40;</span>conn<span class="br0">&#41;</span><span class="sy0">?</span>;
&nbsp;
&nbsp; &nbsp; Ok<span class="br0">&#40;</span>us_adj<span class="br0">&#41;</span>
<span class="br0">&#125;</span>
&nbsp;
&nbsp;
pub fn get_count<span class="br0">&#40;</span>conn <span class="sy0">:</span> <span class="sy0">&amp;</span>PgConnection, user <span class="sy0">:</span> <span class="sy0">&amp;</span>User, adjective <span class="sy0">:</span> <span class="sy0">&amp;</span>Adjective<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> Result<span class="sy0">&lt;</span>Vec<span class="sy0">&lt;</span>UserAdjective<span class="sy0">&gt;</span>, Error<span class="sy0">&gt;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">let</span> query <span class="sy0">=</span> user_adjective<span class="sy0">::</span>table
&nbsp; &nbsp; &nbsp; &nbsp; .<span class="kw3">filter</span><span class="br0">&#40;</span>user_adjective<span class="sy0">::</span>user_id.eq<span class="br0">&#40;</span>user.<span class="kw3">id</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .<span class="kw3">filter</span><span class="br0">&#40;</span>user_adjective<span class="sy0">::</span>adjective_id.eq<span class="br0">&#40;</span>adjective.<span class="kw3">id</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp;
&nbsp; &nbsp; <span class="kw1">let</span> us_adj <span class="sy0">=</span> query.load<span class="sy0">::&lt;</span>UserAdjective<span class="sy0">&gt;</span><span class="br0">&#40;</span>conn<span class="br0">&#41;</span><span class="sy0">?</span>;
&nbsp;
&nbsp; &nbsp; Ok<span class="br0">&#40;</span>us_adj<span class="br0">&#41;</span>
<span class="br0">&#125;</span>
&nbsp;
&nbsp;
pub fn update_us_adj_record<span class="sy0">&lt;</span>'a<span class="sy0">&gt;</span> <span class="br0">&#40;</span>conn <span class="sy0">:</span> <span class="sy0">&amp;</span>PgConnection, user_id <span class="sy0">:</span> <span class="sy0">&amp;</span>i32, adjective_id <span class="sy0">:</span> <span class="sy0">&amp;</span>i32, count_of_repeats <span class="sy0">:</span> <span class="sy0">&amp;</span>i32<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> UserAdjective <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">let</span> count <span class="sy0">=</span> count_of_repeats <span class="sy0">+</span> <span class="nu0">1</span>;
&nbsp; &nbsp; diesel<span class="sy0">::</span>update<span class="br0">&#40;</span>user_adjective<span class="sy0">::</span>table
&nbsp; &nbsp; &nbsp; &nbsp; .<span class="kw3">filter</span><span class="br0">&#40;</span>user_adjective<span class="sy0">::</span>user_id.eq<span class="br0">&#40;</span>user_id<span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .<span class="kw3">filter</span><span class="br0">&#40;</span>user_adjective<span class="sy0">::</span>adjective_id.eq<span class="br0">&#40;</span>adjective_id<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .set<span class="br0">&#40;</span>user_adjective<span class="sy0">::</span>count.eq<span class="br0">&#40;</span>count<span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .get_result<span class="br0">&#40;</span>conn<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .expect<span class="br0">&#40;</span><span class="st0">&quot;Error updating data in the users_adjectives table!&quot;</span><span class="br0">&#41;</span>
<span class="br0">&#125;</span>
&nbsp;
&nbsp;
pub fn create_us_adj_record<span class="sy0">&lt;</span>'a<span class="sy0">&gt;</span><span class="br0">&#40;</span>conn <span class="sy0">:</span> <span class="sy0">&amp;</span>PgConnection, user_id <span class="sy0">:</span> <span class="sy0">&amp;</span>'a i32, adjective_id <span class="sy0">:</span> <span class="sy0">&amp;</span>'a i32<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> UserAdjective <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">let</span> new_usad_record <span class="sy0">=</span> NewUsAdRecord <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; user_id,
&nbsp; &nbsp; &nbsp; &nbsp; adjective_id,
&nbsp; &nbsp; &nbsp; &nbsp; count <span class="sy0">:</span> <span class="sy0">&amp;</span>1i32
&nbsp; &nbsp; <span class="br0">&#125;</span>;
&nbsp;
&nbsp; &nbsp; diesel<span class="sy0">::</span>insert_into<span class="br0">&#40;</span>user_adjective<span class="sy0">::</span>table<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .values<span class="br0">&#40;</span><span class="sy0">&amp;</span>new_usad_record<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .get_result<span class="br0">&#40;</span>conn<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .expect<span class="br0">&#40;</span><span class="st0">&quot;Error saving new record in the users_adjectives table!&quot;</span><span class="br0">&#41;</span>
<span class="br0">&#125;</span>
&nbsp;
&nbsp;
pub fn get_top10_us_adj_for_user<span class="br0">&#40;</span>connection <span class="sy0">:</span> <span class="sy0">&amp;</span>PgConnection, user <span class="sy0">:</span> <span class="sy0">&amp;</span>User<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> Result<span class="sy0">&lt;</span>Vec<span class="sy0">&lt;</span>UserAdjective<span class="sy0">&gt;</span>, Error<span class="sy0">&gt;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">let</span> query <span class="sy0">=</span> user_adjective<span class="sy0">::</span>table
&nbsp; &nbsp; &nbsp; &nbsp; .<span class="kw3">filter</span><span class="br0">&#40;</span>user_adjective<span class="sy0">::</span>user_id.eq<span class="br0">&#40;</span>user.<span class="kw3">id</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .order<span class="br0">&#40;</span>user_adjective<span class="sy0">::</span>adjective_id<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .order<span class="br0">&#40;</span>user_adjective<span class="sy0">::</span>count.desc<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .limit<span class="br0">&#40;</span><span class="nu0">10</span><span class="br0">&#41;</span>;
&nbsp;
&nbsp; &nbsp; <span class="kw1">let</span> us_adj <span class="sy0">:</span> Vec<span class="sy0">&lt;</span>UserAdjective<span class="sy0">&gt;</span> <span class="sy0">=</span> query.load<span class="sy0">::&lt;</span>UserAdjective<span class="sy0">&gt;</span><span class="br0">&#40;</span>connection<span class="br0">&#41;</span><span class="sy0">?</span>;
&nbsp;
&nbsp; &nbsp; Ok<span class="br0">&#40;</span>us_adj<span class="br0">&#41;</span>
<span class="br0">&#125;</span>
&nbsp;
pub fn get_top10_us_adj_for_adjective<span class="br0">&#40;</span>connection <span class="sy0">:</span> <span class="sy0">&amp;</span>PgConnection, adjective <span class="sy0">:</span> <span class="sy0">&amp;</span>Adjective<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> Result<span class="sy0">&lt;</span>Vec<span class="sy0">&lt;</span>UserAdjective<span class="sy0">&gt;</span>, Error<span class="sy0">&gt;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">let</span> query <span class="sy0">=</span> user_adjective<span class="sy0">::</span>table
&nbsp; &nbsp; &nbsp; &nbsp; .<span class="kw3">filter</span><span class="br0">&#40;</span>user_adjective<span class="sy0">::</span>adjective_id.eq<span class="br0">&#40;</span>adjective.<span class="kw3">id</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .order<span class="br0">&#40;</span>user_adjective<span class="sy0">::</span>user_id<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .order<span class="br0">&#40;</span>user_adjective<span class="sy0">::</span>count.desc<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .limit<span class="br0">&#40;</span><span class="nu0">10</span><span class="br0">&#41;</span>;
&nbsp;
&nbsp; &nbsp; <span class="kw1">let</span> us_adj <span class="sy0">:</span> Vec<span class="sy0">&lt;</span>UserAdjective<span class="sy0">&gt;</span> <span class="sy0">=</span> query.load<span class="sy0">::&lt;</span>UserAdjective<span class="sy0">&gt;</span><span class="br0">&#40;</span>connection<span class="br0">&#41;</span><span class="sy0">?</span>;
&nbsp;
&nbsp; &nbsp; Ok<span class="br0">&#40;</span>us_adj<span class="br0">&#41;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Здесь:<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="215625535"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="215625535" style="height: 110px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
</pre></td><td class="de1"><pre class="de1">use database<span class="sy0">::</span>schema<span class="sy0">::*</span>;
use database<span class="sy0">::</span>models<span class="sy0">::</span><span class="br0">&#123;</span> user<span class="sy0">::</span>User
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , adjective<span class="sy0">::</span>Adjective
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , user_adjective<span class="sy0">::</span><span class="br0">&#123;</span> UserAdjective
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , NewUsAdRecord <span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>мы берем информацию о ранее созданной схеме и описанных моделях.<br />
Этот код можно было бы сократить. Например, функции <b>get_top10_us_adj_for_adjective</b> и <b>get_top10_us_adj_for_user</b> можно было бы объединить в одну - сделать это можно с помощью макросов, но, к сожалению, с первого раза я не осилил макросы. Очень уж сложными они мне показались. Возможно, когда до конца разберусь с макросами, перепишу этот код.<br />
Хотел бы остановиться еще на нескольких вещах: <br />
для некоторых функций мы возвращаем результат в виде<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="404452480"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="404452480" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">Result<span class="sy0">&lt;</span>Vec<span class="sy0">&lt;</span>UserAdjective<span class="sy0">&gt;</span>, Error<span class="sy0">&gt;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Тут использован крэйт <b>failure</b>. На 12ой строке написано <b>use failure::Error;</b>. Это сделано для удобства. Почти каждая функция в моем случае будет возвращать свой тип Error. Раньше с этим боролись создавая <b>enum</b> и перечисляя все типы ошибок, которые могут возникнуть. Этот enum использовали в Result. Теперь же появился крэйт failure который делает все за вас.<br />
Вообще, этот Result нужен лишь для того, чтобы не обрабатывать возможную ошибку здесь и сразу, а хотите прокинуть информацию на уровень выше.<br />
Если же вы вообще не хотите возвращать Result на уровень выше, то можете поступить как я сделал в методе <b>update_us_adj_record</b> - я добавил метод <b>expect</b> в котором написал сообщение, которое будет показано в трейсе в случае, если на этом шаге произойдет любая ошибка выполнения.<br />
Что лучше использовать - думаю как и для всего, зависит от ситуации и идеального решения нет.<br />
<br />
<br />
<br />
<font size="3">Middleware</font><br />
На этом уровне все довольно просто - нам нужно уметь выбирать из списков рандомные значения. Так же, нам надо уметь получать и обрабатывать данные, которые мы получаем из базы.<br />
Про рандом просто - есть крэйт <a rel="nofollow noopener noreferrer" href="https://crates.io/crates/rand" target="_blank" title="https://crates.io/crates/rand">rand</a><br />
С его помощью мы из списка вытаскиваем случайный элемент:<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="64954498"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="64954498" style="height: 270px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="de1"><pre class="de1">use rand<span class="sy0">::</span><span class="br0">&#123;</span> thread_rng, Rng <span class="br0">&#125;</span>;
&nbsp;
<span class="sy0">#</span><span class="br0">&#91;</span>derive<span class="br0">&#40;</span>Debug<span class="br0">&#41;</span><span class="br0">&#93;</span>
pub struct RandomData<span class="sy0">&lt;</span>T<span class="sy0">&gt;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; pub value <span class="sy0">:</span> T,
<span class="br0">&#125;</span>
&nbsp;
impl <span class="sy0">&lt;</span>T <span class="sy0">:</span> Clone<span class="sy0">&gt;</span> RandomData<span class="sy0">&lt;</span>T<span class="sy0">&gt;</span> <span class="br0">&#123;</span>
&nbsp;
&nbsp; &nbsp; pub fn new<span class="br0">&#40;</span>vector <span class="sy0">:</span> <span class="sy0">&amp;</span><span class="br0">&#91;</span>T<span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="sy0">-&gt;</span> Self <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> mut rng <span class="sy0">=</span> thread_rng<span class="br0">&#40;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> value <span class="sy0">=</span> rng.choose<span class="br0">&#40;</span><span class="sy0">&amp;</span>vector<span class="br0">&#41;</span>.unwrap<span class="br0">&#40;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; RandomData <span class="br0">&#123;</span> value <span class="sy0">:</span> value.clone<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#125;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Здесь мы используем генерики. T - это обобщенный тип. За ним может скрываться что угодно - i32, String, enum, struct или что вы еще пожелаете. Главное чтобы они реализовывали поведения Clone и Debug. <b>impl &lt;T : Clone&gt; RandomData&lt;T&gt; {</b> означает что для структуры <b>RandomData</b> я имплементирую следующие методы(в моем случае один метод - <b>new</b>). По-хорошему, unwrap() можно было бы заменить на expect() или вообще возвращать Result из метода.<br />
<br />
Второе - работа с данными из базы. Чтобы отобразить их на странице, надо привести их в соответсвующий вид. Вот пример как я преобразую данные для типа User:<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="692544550"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="692544550" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
</pre></td><td class="de1"><pre class="de1"><span class="sy0">#</span><span class="br0">&#91;</span>derive<span class="br0">&#40;</span>Serialize<span class="br0">&#41;</span><span class="br0">&#93;</span>
pub struct DisplayUser <span class="br0">&#123;</span>
&nbsp; &nbsp; pub user <span class="sy0">:</span> User,
&nbsp; &nbsp; pub adj_count <span class="sy0">:</span> Vec<span class="sy0">&lt;</span>AdjCount<span class="sy0">&gt;</span>,
<span class="br0">&#125;</span>
&nbsp;
impl DisplayUser <span class="br0">&#123;</span>
&nbsp; &nbsp; pub fn by_id<span class="br0">&#40;</span>connection <span class="sy0">:</span> <span class="sy0">&amp;</span>DbConn, <span class="kw3">id</span> <span class="sy0">:</span> <span class="sy0">&amp;</span>i32<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> DisplayUser <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> user <span class="sy0">=</span> dbimpl<span class="sy0">::</span>get_user_by_id<span class="br0">&#40;</span><span class="sy0">&amp;</span>connection, <span class="sy0">&amp;</span><span class="kw3">id</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .expect<span class="br0">&#40;</span><span class="sy0">&amp;</span>format<span class="sy0">!</span><span class="br0">&#40;</span><span class="st0">&quot;User with id: {} no found!&quot;</span>, <span class="kw3">id</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; DisplayUser<span class="sy0">::</span>by_user<span class="br0">&#40;</span>connection, user<span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp;
&nbsp; &nbsp; pub fn by_name<span class="br0">&#40;</span>connection <span class="sy0">:</span> <span class="sy0">&amp;</span>DbConn, name <span class="sy0">:</span> <span class="sy0">&amp;</span><span class="kw4">String</span><span class="br0">&#41;</span> <span class="sy0">-&gt;</span> DisplayUser <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> user <span class="sy0">=</span> dbimpl<span class="sy0">::</span>get_user_by_name<span class="br0">&#40;</span><span class="sy0">&amp;</span>connection, <span class="sy0">&amp;</span>name<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .expect<span class="br0">&#40;</span><span class="sy0">&amp;</span>format<span class="sy0">!</span><span class="br0">&#40;</span><span class="st0">&quot;User with name: {} no found!&quot;</span>, name<span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; DisplayUser<span class="sy0">::</span>by_user<span class="br0">&#40;</span>connection, user<span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp;
&nbsp; &nbsp; fn by_user<span class="br0">&#40;</span>connection <span class="sy0">:</span> <span class="sy0">&amp;</span>DbConn, user <span class="sy0">:</span> User<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> DisplayUser <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> top10 <span class="sy0">=</span> dbimpl<span class="sy0">::</span>get_top10_us_adj_for_user<span class="br0">&#40;</span>connection, <span class="sy0">&amp;</span>user<span class="br0">&#41;</span>.
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; expect<span class="br0">&#40;</span><span class="sy0">&amp;</span>format<span class="sy0">!</span><span class="br0">&#40;</span><span class="st0">&quot;User not found in the database. User name is : {}&quot;</span>, user.user_name<span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> mut adj_counts <span class="sy0">:</span> Vec<span class="sy0">&lt;</span>AdjCount<span class="sy0">&gt;</span> <span class="sy0">=</span> Vec<span class="sy0">::</span>new<span class="br0">&#40;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; for top <span class="kw1">in</span> top10 <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> adjective <span class="sy0">=</span> dbimpl<span class="sy0">::</span>get_adjective_by_id<span class="br0">&#40;</span><span class="sy0">&amp;</span>connection, <span class="sy0">&amp;</span>top.adjective_id<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .expect<span class="br0">&#40;</span><span class="sy0">&amp;</span>format<span class="sy0">!</span><span class="br0">&#40;</span><span class="st0">&quot;Adjective not found in the database. adjective_id : {}&quot;</span>, top.adjective_id<span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> count <span class="sy0">=</span> dbimpl<span class="sy0">::</span>get_count<span class="br0">&#40;</span><span class="sy0">&amp;</span>connection, <span class="sy0">&amp;</span>user, <span class="sy0">&amp;</span>adjective<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .expect<span class="br0">&#40;</span><span class="sy0">&amp;</span>format<span class="sy0">!</span><span class="br0">&#40;</span><span class="st0">&quot;Count not found for user_id: {} &nbsp;and adjective_id: {}&quot;</span>, user.<span class="kw3">id</span>, adjective.<span class="kw3">id</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> adj_count <span class="sy0">=</span> AdjCount <span class="br0">&#123;</span> adjective, count <span class="sy0">:</span> count.first<span class="br0">&#40;</span><span class="br0">&#41;</span>.unwrap<span class="br0">&#40;</span><span class="br0">&#41;</span>.count.unwrap<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#125;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; adj_counts.push<span class="br0">&#40;</span>adj_count<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; &nbsp; &nbsp; DisplayUser <span class="br0">&#123;</span> user, adj_count <span class="sy0">:</span> adj_counts <span class="br0">&#125;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp;
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>На чем хотелось бы заострить внимание в среднем уровне, на этом коде:<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="884550558"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="884550558" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</pre></td><td class="de1"><pre class="de1"><span class="sy0">#</span><span class="br0">&#91;</span>derive<span class="br0">&#40;</span>Serialize<span class="br0">&#41;</span><span class="br0">&#93;</span>
pub struct GenerateData <span class="br0">&#123;</span>
&nbsp; &nbsp; random_user_name <span class="sy0">:</span> <span class="kw4">String</span>,
&nbsp; &nbsp; random_adjective_value <span class="sy0">:</span> <span class="kw4">String</span>,
<span class="br0">&#125;</span>
&nbsp;
&nbsp;
impl GenerateData <span class="br0">&#123;</span>
&nbsp; &nbsp; pub fn new<span class="br0">&#40;</span>connection <span class="sy0">:</span> <span class="sy0">&amp;</span>DbConn, allDbData <span class="sy0">:</span> <span class="sy0">&amp;</span>AllDbData<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> GenerateData <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> random_adjective <span class="sy0">=</span> RandomData<span class="sy0">::</span>new<span class="br0">&#40;</span><span class="sy0">&amp;</span>allDbData.adjectives<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> random_user <span class="sy0">=</span> RandomData<span class="sy0">::</span>new<span class="br0">&#40;</span><span class="sy0">&amp;</span>allDbData.users<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; create_or_update_us_adj<span class="br0">&#40;</span><span class="sy0">&amp;</span>connection, <span class="sy0">&amp;</span>random_user.value, <span class="sy0">&amp;</span>random_adjective.value<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; GenerateData <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; random_user_name <span class="sy0">:</span> random_user.value.user_name,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; random_adjective_value <span class="sy0">:</span> random_adjective.value.adjective_value,
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
impl<span class="sy0">&lt;</span>'r<span class="sy0">&gt;</span> Responder<span class="sy0">&lt;</span>'r<span class="sy0">&gt;</span> for GenerateData <span class="br0">&#123;</span>
&nbsp; &nbsp; fn respond_to<span class="br0">&#40;</span>self, _<span class="sy0">:</span> <span class="sy0">&amp;</span>Request<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> response<span class="sy0">::</span>Result<span class="sy0">&lt;</span>'r<span class="sy0">&gt;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; Response<span class="sy0">::</span>build<span class="br0">&#40;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .sized_body<span class="br0">&#40;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Cursor<span class="sy0">::</span>new<span class="br0">&#40;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; format<span class="sy0">!</span><span class="br0">&#40;</span><span class="st0">&quot;&lt;a href=<span class="es0">\&quot;</span>/user/{user}<span class="es0">\&quot;</span>&gt;{user}&lt;/a&gt; cегодня &lt;a href=<span class="es0">\&quot;</span>/adjective/{adjective}<span class="es0">\&quot;</span>&gt;{adjective}&lt;/a&gt;&quot;</span>,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; user <span class="sy0">=</span> self.random_user_name, adjective <span class="sy0">=</span> self.random_adjective_value<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .ok<span class="br0">&#40;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Я хочу <b>GenerateData</b> передавать сразу на фронтенд без каких-либо изменений. Чтобы rocket смог обработать и отобразить эти данные, я должен имплементировать метод <b>respond_to</b> для своей структуры. В принципе, что я и сделал.<br />
<br />
<br />
<br />
<font size="3">Backend</font><br />
Здесь все стандартно для веб-приложений - роутинг и хэндлеры. Начнем с роутинга:<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="817838916"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="817838916" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="de1"><pre class="de1">use rocket;
use database<span class="sy0">::</span>connection;
use backend<span class="sy0">::</span>handler;
use rocket_contrib<span class="sy0">::</span>Template;
use middleware<span class="sy0">::</span>display_data<span class="sy0">::</span>AllDbData;
&nbsp;
pub fn create_routes<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; rocket<span class="sy0">::</span>ignite<span class="br0">&#40;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .manage<span class="br0">&#40;</span>connection<span class="sy0">::</span>init_pool<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .manage<span class="br0">&#40;</span>AllDbData<span class="sy0">::</span>new<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .mount<span class="br0">&#40;</span><span class="st0">&quot;/&quot;</span>,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;routes<span class="sy0">!</span><span class="br0">&#91;</span> handler<span class="sy0">::</span>index
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;, handler<span class="sy0">::</span>all_users
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;, handler<span class="sy0">::</span>all_adjectives
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;, handler<span class="sy0">::</span>get_user_by_id
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;, handler<span class="sy0">::</span>get_user_by_name
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;, handler<span class="sy0">::</span>get_adjective_by_name
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;, handler<span class="sy0">::</span>get_adjective_by_id
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;, handler<span class="sy0">::</span>redirect
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;, handler<span class="sy0">::</span>static_content
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;, handler<span class="sy0">::</span>generate_new_one
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#93;</span>,
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .attach<span class="br0">&#40;</span>Template<span class="sy0">::</span>fairing<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .<span class="kw3">catch</span><span class="br0">&#40;</span>catchers<span class="sy0">!</span><span class="br0">&#91;</span>handler<span class="sy0">::</span>not_found<span class="br0">&#93;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; .launch<span class="br0">&#40;</span><span class="br0">&#41;</span>;
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Первым делом, передаем пул коннекта к базе рокету <b>manage(connection::init_pool())</b>, потом вытаскиваем все данные из базы (потому что не очень хорошая идея ходить на каждый чих в базу за чтением данных). Ну а дальше перечисляем все хэндлеры которые есть в нашем приложении.<br />
Строчка <b>.attach(Template::fairing())</b> означает что я хочу использовать шаблоны для фронтенда. А строчка <b>.catch(catchers![handler::not_found])</b> говорит какую страницу показывать если пользователь вдруг пойдет не туда. Проще говоря, 404ая страница. Ну и <b>.launch();</b> - стартуем Rocket.<br />
С хэндлерами тоже все просто:<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="308378986"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="308378986" style="height: 110px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
</pre></td><td class="de1"><pre class="de1"><span class="sy0">#</span><span class="br0">&#91;</span>get<span class="br0">&#40;</span><span class="st0">&quot;/&quot;</span><span class="br0">&#41;</span><span class="br0">&#93;</span>
fn index<span class="br0">&#40;</span>connection <span class="sy0">:</span> DbConn, allDbData <span class="sy0">:</span> State<span class="sy0">&lt;</span>AllDbData<span class="sy0">&gt;</span><span class="br0">&#41;</span> <span class="sy0">-&gt;</span> Template <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">let</span> context <span class="sy0">=</span> IndexData<span class="sy0">::</span>new<span class="br0">&#40;</span><span class="sy0">&amp;</span>connection, <span class="sy0">&amp;</span>allDbData<span class="br0">&#41;</span>;
&nbsp; &nbsp; Template<span class="sy0">::</span>render<span class="br0">&#40;</span><span class="st0">&quot;index&quot;</span>, <span class="sy0">&amp;</span>context<span class="br0">&#41;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div><b>#[get(&quot;/&quot;)]</b> - юзер должен зайти сюда, чтобы увидеть шаблон, который описан в файлике под названием index.<br />
Еще пример из хэндлеров:<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="544871778"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="544871778" style="height: 222px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="de1"><pre class="de1"><span class="sy0">#</span><span class="br0">&#91;</span>get<span class="br0">&#40;</span><span class="st0">&quot;/user/&lt;id&gt;&quot;</span><span class="br0">&#41;</span><span class="br0">&#93;</span>
fn get_user_by_id<span class="br0">&#40;</span><span class="kw3">id</span><span class="sy0">:</span> i32, connection<span class="sy0">:</span> DbConn<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> Template <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">let</span> context <span class="sy0">=</span> DisplayUser<span class="sy0">::</span>by_id<span class="br0">&#40;</span><span class="sy0">&amp;</span>connection, <span class="sy0">&amp;</span><span class="kw3">id</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; Template<span class="sy0">::</span>render<span class="br0">&#40;</span><span class="st0">&quot;user&quot;</span>, <span class="sy0">&amp;</span>context<span class="br0">&#41;</span>
<span class="br0">&#125;</span>
&nbsp;
&nbsp;
<span class="sy0">#</span><span class="br0">&#91;</span>get<span class="br0">&#40;</span><span class="st0">&quot;/user/&lt;name&gt;&quot;</span>, rank <span class="sy0">=</span> <span class="nu0">2</span><span class="br0">&#41;</span><span class="br0">&#93;</span>
fn get_user_by_name<span class="br0">&#40;</span>name<span class="sy0">:</span> <span class="kw4">String</span>, connection<span class="sy0">:</span> DbConn<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> Template <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">let</span> context <span class="sy0">=</span> DisplayUser<span class="sy0">::</span>by_name<span class="br0">&#40;</span><span class="sy0">&amp;</span>connection, <span class="sy0">&amp;</span>name<span class="br0">&#41;</span>;
&nbsp; &nbsp; Template<span class="sy0">::</span>render<span class="br0">&#40;</span><span class="st0">&quot;user&quot;</span>, <span class="sy0">&amp;</span>context<span class="br0">&#41;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Здесь мы показываем данные юзера, если пользователь зайдет на страницу по id юзера <b>#[get(&quot;/user/&lt;id&gt;&quot;)]</b> или по его имени <b>#[get(&quot;/user/&lt;name&gt;&quot;, rank = 2)]</b>. rank=2 значит что у способа идентификации юзера по имени приоритет ниже.<br />
Очень и очень много времени у меня заняло как сделать так, чтобы при заходе на страницу, пользователю показывались не только данные от rust кода, но и красивости от фронтенда. Это было по-настоящему сложно понять, но решение простое:<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="8064808"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="8064808" style="height: 94px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
</pre></td><td class="de1"><pre class="de1"><span class="sy0">#</span><span class="br0">&#91;</span>get<span class="br0">&#40;</span><span class="st0">&quot;/static/&lt;file..&gt;&quot;</span><span class="br0">&#41;</span><span class="br0">&#93;</span>
fn static_content<span class="br0">&#40;</span>file<span class="sy0">:</span> PathBuf<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> Result<span class="sy0">&lt;</span>NamedFile, StdIoError<span class="sy0">&gt;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp;NamedFile<span class="sy0">::</span>open<span class="br0">&#40;</span>Path<span class="sy0">::</span>new<span class="br0">&#40;</span><span class="st0">&quot;static/&quot;</span><span class="br0">&#41;</span>.join<span class="br0">&#40;</span>file<span class="br0">&#41;</span><span class="br0">&#41;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Этот метод необходимо прописать в хэндлерах чтобы из папки static у нас начали тянуться css, js и прочие статик-файлы.<br />
<br />
<br />
<br />
<font size="3">Frontend</font><br />
Как я уже говорил, я имею довольно мало отношения к вебу. Я отлично понимаю как работают веб-приложения на бекенде, как их задеплоить на сервере, как настроить почти любой веб-сервер, но что происходит на фронтенде - для меня всегда было большой загадкой. Чтож, у Rocket довольно мало инструментов для работы с фронтендом. Честно говоря, по началу я думал что придется использовать фреймоврк YEW(придется - потому что для моих целей это как из пушки по воробьям). Но внимательней прочитав документацию Rocket, я увидел что есть поддержка <a rel="nofollow noopener noreferrer" href="https://handlebarsjs.com" target="_blank" title="https://handlebarsjs.com">Handlebars</a>. Изучив этот инструмент, я понял что это то что нужно! <a rel="nofollow noopener noreferrer" href="https://handlebarsjs.com" target="_blank" title="https://handlebarsjs.com">Handlebars</a> - клиентский шаблонизатор для JavaScript. <br />
Вот так выглядит index.html.hbs:<br />
<div class="codeblock"><table class="html5"><thead><tr><td colspan="2" id="653088959"  class="head">HTML5</td></tr></thead><tbody><tr class="li1"><td><div id="653088959" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</pre></td><td class="de1"><pre class="de1"><span class="sc0">&lt;!DOCTYPE html&gt;</span>
<span class="sc2">&lt;<span class="kw2">html</span>&gt;</span>
&nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">head</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">meta</span> <span class="kw3">charset</span><span class="sy0">=</span><span class="st0">&quot;utf-8&quot;</span> <span class="sy0">/</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">title</span>&gt;</span>Кто какой<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">title</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; {{&gt; common/meta/header }}
&nbsp; &nbsp; <span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">head</span>&gt;</span>
&nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">body</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">script</span> <span class="kw3">src</span><span class="sy0">=</span><span class="st0">&quot;/static/generate.js&quot;</span>&gt;&lt;<span class="sy0">/</span><span class="kw2">script</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">br</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">span</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;h2 text-success flex-centered&quot;</span>&gt;</span>Нарандомили:<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">span</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">p</span> <span class="kw3">align</span><span class="sy0">=</span><span class="st0">&quot;center&quot;</span> <span class="kw3">id</span><span class="sy0">=</span><span class="st0">&quot;display_random_data&quot;</span>&gt;&lt;<span class="kw2">a</span> <span class="kw3">href</span><span class="sy0">=</span><span class="st0">&quot;/user/{{random_user_name}}&quot;</span>&gt;</span>{{random_user_name}}<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">a</span>&gt;</span> сегодня <span class="sc2">&lt;<span class="kw2">a</span> <span class="kw3">href</span><span class="sy0">=</span><span class="st0">&quot;/adjective/{{random_adjective_value}}&quot;</span>&gt;</span>{{random_adjective_value}}<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">a</span>&gt;&lt;<span class="sy0">/</span><span class="kw2">p</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">button</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;btn btn-primary centered&quot;</span> <span class="kw3">onclick</span><span class="sy0">=</span><span class="st0">&quot;generate()&quot;</span>&gt;</span>Сгенерируй снова!<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">button</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">br</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">br</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">h2</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;text-gray&quot;</span>&gt;</span>Топ 10 сочетаний:<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">h2</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">table</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;table table-striped text-center&quot;</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">thead</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">tr</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">th</span>&gt;</span>Кто<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">th</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">th</span>&gt;</span>Какой<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">th</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">th</span>&gt;</span>Количество совпадений<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">th</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">tr</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">thead</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">tbody</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {{#each usadjcounts}}
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">tr</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;active&quot;</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">td</span>&gt;&lt;<span class="kw2">a</span> <span class="kw3">href</span><span class="sy0">=</span><span class="st0">&quot;/user/{{this.user.id}}&quot;</span>&gt;</span>{{this.user.user_name}}<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">a</span>&gt;&lt;<span class="sy0">/</span><span class="kw2">td</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">td</span>&gt;&lt;<span class="kw2">a</span> <span class="kw3">href</span><span class="sy0">=</span><span class="st0">&quot;/adjective/{{this.adjective.id}}&quot;</span>&gt;</span>{{this.adjective.adjective_value}}<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">a</span>&gt;&lt;<span class="sy0">/</span><span class="kw2">td</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">td</span>&gt;</span>{{this.count}}<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">td</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">tr</span>&gt;</span>
&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {{/each}}
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">tbody</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">table</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; {{&gt; common/footer }}
&nbsp; &nbsp; <span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">body</span>&gt;</span>
<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">html</span>&gt;</span></pre></td></tr></table></div></td></tr></tbody></table></div>И generate.js:<br />
<div class="codeblock"><table class="javascript"><thead><tr><td colspan="2" id="923771953"  class="head">JavaScript</td></tr></thead><tbody><tr class="li1"><td><div id="923771953" style="height: 174px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
</pre></td><td class="de1"><pre class="de1"><span class="kw1">function</span> generate<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">const</span> Http <span class="sy0">=</span> <span class="kw1">new</span> XMLHttpRequest<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw1">const</span> url<span class="sy0">=</span><span class="st0">'./generate_new_one'</span><span class="sy0">;</span>
&nbsp; &nbsp; Http.<span class="me1">open</span><span class="br0">&#40;</span><span class="st0">&quot;POST&quot;</span><span class="sy0">,</span> url<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; Http.<span class="me1">send</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; Http.<span class="me1">onreadystatechange</span><span class="sy0">=</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span><span class="sy0">=&gt;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; document.<span class="me1">getElementById</span><span class="br0">&#40;</span><span class="st0">&quot;display_random_data&quot;</span><span class="br0">&#41;</span>.<span class="me1">innerHTML</span> <span class="sy0">=</span> Http.<span class="me1">responseText</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Здесь я просто в хэндлерах на странице generate_new_one генерирую новое сочетание user-adjective и вывожу на странице получившиеся данные.<br />
А вот этот участок кода:<br />
<div class="codeblock"><table class="html5"><thead><tr><td colspan="2" id="541252758"  class="head">HTML5</td></tr></thead><tbody><tr class="li1"><td><div id="541252758" style="height: 158px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
</pre></td><td class="de1"><pre class="de1">&nbsp;{{#each usadjcounts}}
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">tr</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;active&quot;</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">td</span>&gt;&lt;<span class="kw2">a</span> <span class="kw3">href</span><span class="sy0">=</span><span class="st0">&quot;/user/{{this.user.id}}&quot;</span>&gt;</span>{{this.user.user_name}}<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">a</span>&gt;&lt;<span class="sy0">/</span><span class="kw2">td</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">td</span>&gt;&lt;<span class="kw2">a</span> <span class="kw3">href</span><span class="sy0">=</span><span class="st0">&quot;/adjective/{{this.adjective.id}}&quot;</span>&gt;</span>{{this.adjective.adjective_value}}<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">a</span>&gt;&lt;<span class="sy0">/</span><span class="kw2">td</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="kw2">td</span>&gt;</span>{{this.count}}<span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">td</span>&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">tr</span>&gt;</span>
&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {{/each}}</pre></td></tr></table></div></td></tr></tbody></table></div>Заполняется довольно просто:<br />
в хэндлерах написано:<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="129167900"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="129167900" style="height: 110px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
</pre></td><td class="de1"><pre class="de1"><span class="sy0">#</span><span class="br0">&#91;</span>get<span class="br0">&#40;</span><span class="st0">&quot;/&quot;</span><span class="br0">&#41;</span><span class="br0">&#93;</span>
fn index<span class="br0">&#40;</span>connection <span class="sy0">:</span> DbConn, allDbData <span class="sy0">:</span> State<span class="sy0">&lt;</span>AllDbData<span class="sy0">&gt;</span><span class="br0">&#41;</span> <span class="sy0">-&gt;</span> Template <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">let</span> context <span class="sy0">=</span> IndexData<span class="sy0">::</span>new<span class="br0">&#40;</span><span class="sy0">&amp;</span>connection, <span class="sy0">&amp;</span>allDbData<span class="br0">&#41;</span>;
&nbsp; &nbsp; Template<span class="sy0">::</span>render<span class="br0">&#40;</span><span class="st0">&quot;index&quot;</span>, <span class="sy0">&amp;</span>context<span class="br0">&#41;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Смотрим определение <b>IndexData</b>:<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="467583912"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="467583912" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
</pre></td><td class="de1"><pre class="de1"><span class="sy0">#</span><span class="br0">&#91;</span>derive<span class="br0">&#40;</span>Serialize<span class="br0">&#41;</span><span class="br0">&#93;</span>
pub struct IndexData <span class="br0">&#123;</span>
&nbsp; &nbsp; random_user_name <span class="sy0">:</span> <span class="kw4">String</span>,
&nbsp; &nbsp; random_adjective_value <span class="sy0">:</span> <span class="kw4">String</span>,
&nbsp; &nbsp; usadjcounts <span class="sy0">:</span> Vec<span class="sy0">&lt;</span>UsAdjCount<span class="sy0">&gt;</span>,
<span class="br0">&#125;</span>
&nbsp;
impl IndexData <span class="br0">&#123;</span>
&nbsp; &nbsp; pub fn new<span class="br0">&#40;</span>connection <span class="sy0">:</span> <span class="sy0">&amp;</span>DbConn, allDbData <span class="sy0">:</span> <span class="sy0">&amp;</span>AllDbData<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> IndexData <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> most_frequent <span class="sy0">=</span> dbimpl<span class="sy0">::</span>get_top10_all<span class="br0">&#40;</span><span class="sy0">&amp;</span>connection<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .unwrap_or<span class="br0">&#40;</span>Vec<span class="sy0">::</span>new<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> mut usadjcounts <span class="sy0">=</span> Vec<span class="sy0">::</span>new<span class="br0">&#40;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; for most <span class="kw1">in</span> most_frequent.iter<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> user <span class="sy0">=</span> dbimpl<span class="sy0">::</span>get_user_by_id<span class="br0">&#40;</span><span class="sy0">&amp;</span>connection, <span class="sy0">&amp;</span>most.user_id<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .expect<span class="br0">&#40;</span><span class="sy0">&amp;</span>format<span class="sy0">!</span><span class="br0">&#40;</span><span class="st0">&quot;User not found in the database. user_id : {}&quot;</span>, most.user_id<span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> adjective <span class="sy0">=</span> dbimpl<span class="sy0">::</span>get_adjective_by_id<span class="br0">&#40;</span><span class="sy0">&amp;</span>connection, <span class="sy0">&amp;</span>most.adjective_id<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .expect<span class="br0">&#40;</span><span class="sy0">&amp;</span>format<span class="sy0">!</span><span class="br0">&#40;</span><span class="st0">&quot;Adjective not found in the database. adjective_id : {}&quot;</span>, most.adjective_id<span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> count <span class="sy0">=</span> most.count
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .expect<span class="br0">&#40;</span><span class="sy0">&amp;</span>format<span class="sy0">!</span><span class="br0">&#40;</span><span class="st0">&quot;Cannot get count from database for user_id : {}&quot;</span>, most.user_id<span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> usadjcount <span class="sy0">=</span> UsAdjCount <span class="br0">&#123;</span> user, adjective, count <span class="br0">&#125;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; usadjcounts.push<span class="br0">&#40;</span>usadjcount<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> random_adjective <span class="sy0">=</span> RandomData<span class="sy0">::</span>new<span class="br0">&#40;</span><span class="sy0">&amp;</span>allDbData.adjectives<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> random_user <span class="sy0">=</span> RandomData<span class="sy0">::</span>new<span class="br0">&#40;</span><span class="sy0">&amp;</span>allDbData.users<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; create_or_update_us_adj<span class="br0">&#40;</span><span class="sy0">&amp;</span>connection, <span class="sy0">&amp;</span>random_user.value, <span class="sy0">&amp;</span>random_adjective.value<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; IndexData <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; random_user_name <span class="sy0">:</span> random_user.value.user_name,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; random_adjective_value <span class="sy0">:</span> random_adjective.value.adjective_value,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; usadjcounts,
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>то есть, шаблону я передаю структуру с содержимым: <b>random_user_name : String</b>, <b>random_adjective_value : String</b>, <b>usadjcounts : Vec&lt;UsAdjCount&gt;</b>, а внутри шаблона я оперирую теми же данными: <b>{{#each usadjcounts}}</b>.<br />
Осталось навести красоту с помощью css. Я выбрал Spectre CSS - просто закинул в папку которая будет отдавать статику все файлики этого CSS фреймворка.<br />
<br />
<br />
<br />
<font size="3">Опции Rocket</font><br />
Rocket позволяет настроить работу с окружением своим конфигурационным toml-файлом.<br />
Вот он в моем случае:<br />
<div class="codeblock"><table class="json"><thead><tr><td colspan="2" id="491679896"  class="head">JSON</td></tr></thead><tbody><tr class="li1"><td><div id="491679896" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#91;</span>global.<span class="me1">limits</span><span class="br0">&#93;</span>
forms <span class="sy0">=</span> <span class="nu0">32768</span>
&nbsp;
<span class="br0">&#91;</span>development<span class="br0">&#93;</span>
address <span class="sy0">=</span> <span class="st0">&quot;localhost&quot;</span>
port <span class="sy0">=</span> <span class="nu0">8000</span>
workers <span class="sy0">=</span> <span class="nu0">4</span>
keep_alive <span class="sy0">=</span> <span class="nu0">5</span>
log <span class="sy0">=</span> <span class="st0">&quot;normal&quot;</span>
template_dir <span class="sy0">=</span> <span class="st0">&quot;templates/&quot;</span>
&nbsp;
&nbsp;
<span class="br0">&#91;</span>staging<span class="br0">&#93;</span>
address <span class="sy0">=</span> <span class="st0">&quot;0.0.0.0&quot;</span>
port <span class="sy0">=</span> <span class="nu0">8000</span>
workers <span class="sy0">=</span> <span class="nu0">8</span>
keep_alive <span class="sy0">=</span> <span class="nu0">5</span>
log <span class="sy0">=</span> <span class="st0">&quot;normal&quot;</span>
template_dir <span class="sy0">=</span> <span class="st0">&quot;templates/&quot;</span>
&nbsp;
<span class="br0">&#91;</span>production<span class="br0">&#93;</span>
address <span class="sy0">=</span> <span class="st0">&quot;0.0.0.0&quot;</span>
port <span class="sy0">=</span> <span class="nu0">8000</span>
workers <span class="sy0">=</span> <span class="nu0">12</span>
keep_alive <span class="sy0">=</span> <span class="nu0">5</span>
log <span class="sy0">=</span> <span class="st0">&quot;critical&quot;</span>
template_dir <span class="sy0">=</span> <span class="st0">&quot;templates/&quot;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Здесь прописаны варианты работы в различных режимах (параметры в которых будет сбилжено/запущено приложение с помощью cargo).<br />
Подробнее о конфигурационном файле Rocket написано <a rel="nofollow noopener noreferrer" href="https://rocket.rs/guide/configuration/" target="_blank" title="https://rocket.rs/guide/configuration/">здесь</a><br />
<br />
<br />
<br />
<font size="3">Итого</font><br />
Я написал сайт пару месяцев назад. Для старой версии rustc - компилятора rust. И с запуском этого приложения с новой версией компилятора могут возникнуть проблемы. Но cargo - отличная вещь! Достаточно указать версию компилятора с которой ты хочешь запустить приложение и это будет работать!<br />
В моем случае команда выглядит так:<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="142839598"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="142839598" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">cargo +nightly-<span class="nu0">2018</span>-07-<span class="nu0">24</span> run</pre></td></tr></table></div></td></tr></tbody></table></div>Я очень доволен <a rel="nofollow noopener noreferrer" href="https://rocket.rs/" target="_blank" title="https://rocket.rs/">Rocket</a>. Так же, отличные возможности показал <a rel="nofollow noopener noreferrer" href="https://diesel.rs/" target="_blank" title="https://diesel.rs/">diesel</a>. <br />
Rust - великолепный язык. Писать на нем сплошное удовольствие. Советую и вам попробовать.<br />
Как работает мой сайт-шутка можно глянуть <a rel="nofollow noopener noreferrer" href="http://130.193.58.61" target="_blank" title="http://130.193.58.61">здесь</a>. Код приложения доступен <a rel="nofollow noopener noreferrer" href="https://github.com/loothood/joke" target="_blank" title="https://github.com/loothood/joke">здесь</a>.</div>

]]></content:encoded>
			<dc:creator>loothood</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/606805/5421.html</guid>
		</item>
		<item>
			<title>YEW - веб фреймворк</title>
			<link>https://www.cyberforum.ru/blogs/606805/5081.html</link>
			<pubDate>Sun, 31 Dec 2017 16:07:47 GMT</pubDate>
			<description>YEW - Elm/React/Angular-подобный фреймворк для создания веб-приложений с помощью Rust. 
Это...</description>
			<content:encoded><![CDATA[<div>YEW - Elm/React/Angular-подобный фреймворк для создания веб-приложений с помощью Rust.<br />
Это инструмент для тех, кто хочет использовать Rust везде, даже для написания клиентских интерфейсов в браузере.<br />
<br />
Фичи фреймворка:<ul><li>JSX-подобные шаблоны(со стандартными однострочными или многострочными комментариями)</li>
<li>Чистый код Rust в html шаблонах</li>
<li>В ногу с WebAssembly</li>
<li>MVC подход идентичен платформе ELM</li>
<li>Просто начать, потому что фреймворк позволяет использовать грязный код(с побочными эффектами) внутри шаблонов</li>
<li>Управление приложением как в Redux</li>
<li>Виртуальный DOM для изменений в дереве с небольшими трудозатратами</li>
<li>Поддерживайте совместимость со сторонними тулузами: serde, chrono и другими</li>
<li>... и наиболее важное - Rust!</li>
</ul><br />
Пример приложения:<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="453341542"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="453341542" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</pre></td><td class="de1"><pre class="de1"><span class="kw2">extern</span> crate chrono<span class="sy0">;</span>
<span class="co2">#[macro_use] extern crate yew;</span>
&nbsp;
use chrono<span class="sy0">::</span><span class="me2">prelude</span><span class="sy0">::*;</span>
use yew<span class="sy0">::</span><span class="me2">html</span><span class="sy0">;</span>
&nbsp;
<span class="kw4">struct</span> Model <span class="br0">&#123;</span> value<span class="sy0">:</span> i64 <span class="br0">&#125;</span>
&nbsp;
<span class="kw2">enum</span> Msg <span class="br0">&#123;</span>
&nbsp; &nbsp; Increment<span class="sy0">,</span>
&nbsp; &nbsp; Decrement<span class="sy0">,</span>
<span class="br0">&#125;</span>
&nbsp;
fn update<span class="br0">&#40;</span>model<span class="sy0">:</span> <span class="sy0">&amp;</span>mut Model<span class="sy0">,</span> msg<span class="sy0">:</span> Msg<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; match msg <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; Msg<span class="sy0">::</span><span class="me2">Increment</span> <span class="sy0">=&gt;</span> <span class="br0">&#123;</span> model.<span class="me1">value</span> <span class="sy0">=</span> model.<span class="me1">value</span> <span class="sy0">+</span> <span class="nu0">1</span><span class="sy0">;</span> <span class="br0">&#125;</span>
&nbsp; &nbsp; &nbsp; &nbsp; Msg<span class="sy0">::</span><span class="me2">Decrement</span> <span class="sy0">=&gt;</span> <span class="br0">&#123;</span> model.<span class="me1">value</span> <span class="sy0">=</span> model.<span class="me1">value</span> <span class="sy0">-</span> <span class="nu0">1</span><span class="sy0">;</span> <span class="br0">&#125;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
fn view<span class="br0">&#40;</span>model<span class="sy0">:</span> <span class="sy0">&amp;</span>Model<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> html<span class="sy0">::</span><span class="me2">Html</span><span class="sy0">&lt;</span>Msg<span class="sy0">&gt;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; html<span class="sy0">!</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&lt;</span>div<span class="sy0">&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&lt;</span>nav class<span class="sy0">=</span><span class="st0">&quot;menu&quot;</span><span class="sy0">,&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&lt;</span>button onclick<span class="sy0">=|</span>_<span class="sy0">|</span> Msg<span class="sy0">::</span><span class="me2">Increment</span><span class="sy0">,&gt;</span><span class="br0">&#123;</span> <span class="st0">&quot;Increment&quot;</span> <span class="br0">&#125;</span><span class="sy0">&lt;/</span>button<span class="sy0">&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// No more html comments! use Rust/JS style</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&lt;</span>button onclick<span class="sy0">=|</span>_<span class="sy0">|</span> Msg<span class="sy0">::</span><span class="me2">Decrement</span><span class="sy0">,&gt;</span><span class="br0">&#123;</span> <span class="st0">&quot;Decrement&quot;</span> <span class="br0">&#125;</span><span class="sy0">&lt;/</span>button<span class="sy0">&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&lt;/</span>nav<span class="sy0">&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&lt;</span>p<span class="sy0">&gt;</span><span class="br0">&#123;</span> model.<span class="me1">value</span> <span class="br0">&#125;</span><span class="sy0">&lt;/</span>p<span class="sy0">&gt;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&lt;</span>p<span class="sy0">&gt;</span><span class="br0">&#123;</span> Local<span class="sy0">::</span><span class="me2">now</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#125;</span><span class="sy0">&lt;/</span>p<span class="sy0">&gt;</span> <span class="coMULTI">/* with side-effects! */</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&lt;/</span>div<span class="sy0">&gt;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
fn main<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; let model <span class="sy0">=</span> Model <span class="br0">&#123;</span> value<span class="sy0">:</span> <span class="nu0">0</span> <span class="br0">&#125;</span><span class="sy0">;</span>
&nbsp; &nbsp; html<span class="sy0">::</span><span class="me2">program</span><span class="br0">&#40;</span>model<span class="sy0">,</span> update<span class="sy0">,</span> view<span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Больше примеров вы можете найти <a rel="nofollow noopener noreferrer" href="https://github.com/DenisKolodin/yew/blob/master/examples/todomvc/src/main.rs" target="_blank" title="https://github.com/DenisKolodin/yew/blob/master/examples/todomvc/src/main.rs">здесь</a><br />
<br />
<br />
<a rel="nofollow noopener noreferrer" href="https://users.rust-lang.org/t/yew-a-framework-for-client-side-web-apps/14597" target="_blank" title="https://users.rust-lang.org/t/yew-a-framework-for-client-side-web-apps/14597">Оригинал</a><br />
<br />
Всех С Наступающий Новым Годом!!!</div>

]]></content:encoded>
			<dc:creator>loothood</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/606805/5081.html</guid>
		</item>
		<item>
			<title>Работа с событиями в Rust</title>
			<link>https://www.cyberforum.ru/blogs/606805/5075.html</link>
			<pubDate>Wed, 27 Dec 2017 09:26:14 GMT</pubDate>
			<description>*Что* 
Шаблон наблюдатель - это шаблон проектирования в котором объект, называемый субъектом,...</description>
			<content:encoded><![CDATA[<div><b><font size="3">Что</font></b><br />
Шаблон наблюдатель - это шаблон проектирования в котором объект, называемый субъектом, хранит список наблюдаемых объектов, называемых наблюдателями, и следит за изменениями в их состояниях, обычно вызывая один из их методов. <a rel="nofollow noopener noreferrer" href="https://en.wikipedia.org/wiki/Observer_pattern" target="_blank" title="https://en.wikipedia.org/wiki/Observer_pattern">Подробнее</a>.<br />
<br />
Перехват событий(или коллбеки) - простой способ реализации шаблона наблюдения когда субъект сообщает наблюдателям, что произошло то или иное событие.<br />
<br />
<br />
<b><font size="3">Почему</font></b><br />
Перехват событий может быть использован в событийно-управляемым программировании(event-driven programming), в котором поток программы разбит на различные события. Такие как действия пользователя, вывод данных, сообщения из потоков\программ. <a rel="nofollow noopener noreferrer" href="https://en.wikipedia.org/wiki/Event-driven_programming" target="_blank" title="https://en.wikipedia.org/wiki/Event-driven_programming">Подробнее</a><br />
<br />
<br />
<b><font size="3">Как</font></b><br />
Мы используем особенность Rust под названием трейты(trains), чтобы определить ожидаемое поведение интерфейса событий. Трейты будут состоять из обработчика событий, который, в свою очередь, по заголовку событий будет определять что это за событие.<br />
<br />
Использование трейтов делает наш обработчик событий универсальным(они могут быть любого типа). Все, что надо будет сделать - реализовать трейт на каждое событие.<br />
<br />
Для примера, я реализовал событийно-управляемый Логгер(Logger), который записывает события TCP подключений.<br />
<br />
Ниже трейт который реализует интерфейс событий для TCP подключений:<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="162073006"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="162073006" style="height: 174px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
</pre></td><td class="de1"><pre class="de1"><span class="co2">#[allow(unused_variables)]</span>
pub trait Events <span class="br0">&#123;</span>
&nbsp; &nbsp; fn on_connect<span class="br0">&#40;</span><span class="sy0">&amp;</span>self<span class="sy0">,</span> host<span class="sy0">:</span> <span class="sy0">&amp;</span>str<span class="sy0">,</span> port<span class="sy0">:</span> i32<span class="br0">&#41;</span> <span class="br0">&#123;</span><span class="br0">&#125;</span>
&nbsp; &nbsp; fn on_error<span class="br0">&#40;</span><span class="sy0">&amp;</span>self<span class="sy0">,</span> err<span class="sy0">:</span> <span class="sy0">&amp;</span>str<span class="br0">&#41;</span> <span class="br0">&#123;</span><span class="br0">&#125;</span>
&nbsp; &nbsp; fn on_read<span class="br0">&#40;</span><span class="sy0">&amp;</span>self<span class="sy0">,</span> resp<span class="sy0">:</span> <span class="sy0">&amp;</span><span class="br0">&#91;</span>u8<span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><span class="br0">&#125;</span>
&nbsp; &nbsp; fn on_shutdown<span class="br0">&#40;</span><span class="sy0">&amp;</span>self<span class="br0">&#41;</span> <span class="br0">&#123;</span><span class="br0">&#125;</span>
&nbsp; &nbsp; fn on_pre_read<span class="br0">&#40;</span><span class="sy0">&amp;</span>self<span class="br0">&#41;</span> <span class="br0">&#123;</span><span class="br0">&#125;</span>
&nbsp; &nbsp; fn on_post_read<span class="br0">&#40;</span><span class="sy0">&amp;</span>self<span class="br0">&#41;</span> <span class="br0">&#123;</span><span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Реализация обработчика событий для логгера выглядит так:<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="852906334"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="852906334" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="de1"><pre class="de1"><span class="kw4">struct</span> Logger<span class="sy0">;</span>
&nbsp;
impl Events <span class="kw1">for</span> Logger <span class="br0">&#123;</span>
&nbsp; &nbsp; fn on_connect<span class="br0">&#40;</span><span class="sy0">&amp;</span>self<span class="sy0">,</span> host<span class="sy0">:</span> <span class="sy0">&amp;</span>str<span class="sy0">,</span> port<span class="sy0">:</span> i32<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; println<span class="sy0">!</span><span class="br0">&#40;</span><span class="st0">&quot;Connected to {} on port {}&quot;</span><span class="sy0">,</span> host<span class="sy0">,</span> port<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp;
&nbsp; &nbsp; fn on_error<span class="br0">&#40;</span><span class="sy0">&amp;</span>self<span class="sy0">,</span> err<span class="sy0">:</span> <span class="sy0">&amp;</span>str<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; println<span class="sy0">!</span><span class="br0">&#40;</span><span class="st0">&quot;error: {}&quot;</span><span class="sy0">,</span> err<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp;
&nbsp; &nbsp; fn on_read<span class="br0">&#40;</span><span class="sy0">&amp;</span>self<span class="sy0">,</span> resp<span class="sy0">:</span> <span class="sy0">&amp;</span><span class="br0">&#91;</span>u8<span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; print<span class="sy0">!</span><span class="br0">&#40;</span><span class="st0">&quot;{}&quot;</span><span class="sy0">,</span> str<span class="sy0">::</span><span class="me2">from_utf8</span><span class="br0">&#40;</span>resp<span class="br0">&#41;</span>.<span class="me1">unwrap</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp;
&nbsp; &nbsp; fn on_shutdown<span class="br0">&#40;</span><span class="sy0">&amp;</span>self<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; println<span class="sy0">!</span><span class="br0">&#40;</span><span class="st0">&quot;Connection closed.&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp;
&nbsp; &nbsp; fn on_pre_read<span class="br0">&#40;</span><span class="sy0">&amp;</span>self<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; println<span class="sy0">!</span><span class="br0">&#40;</span><span class="st0">&quot;Receiving content:<span class="es1">\n</span>&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp;
&nbsp; &nbsp; fn on_post_read<span class="br0">&#40;</span><span class="sy0">&amp;</span>self<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; println<span class="sy0">!</span><span class="br0">&#40;</span><span class="st0">&quot;<span class="es1">\n</span>Finished receiving content.&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Логгер работает как Наблюдатель, который получает уведомления о происшедших событиях.<br />
<br />
Далее, у нас есть структура HttpClient, в имплементации которой выполняются сетевые tcp вызовы и уведомляют наблюдателей, о том что событие произошло.<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="312963142"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="312963142" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
</pre></td><td class="de1"><pre class="de1"><span class="kw4">struct</span> HttpClient <span class="br0">&#123;</span>
&nbsp; &nbsp; host<span class="sy0">:</span> String<span class="sy0">,</span>
&nbsp; &nbsp; port<span class="sy0">:</span> i32<span class="sy0">,</span>
&nbsp; &nbsp; hooks<span class="sy0">:</span> Vec<span class="sy0">&lt;</span>Box<span class="sy0">&lt;</span>Events<span class="sy0">&gt;&gt;,</span>
<span class="br0">&#125;</span>
&nbsp;
impl HttpClient <span class="br0">&#123;</span>
&nbsp; &nbsp; pub fn new<span class="br0">&#40;</span>host<span class="sy0">:</span> <span class="sy0">&amp;</span>str<span class="sy0">,</span> port<span class="sy0">:</span> i32<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> Self <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; Self <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; host<span class="sy0">:</span> host.<span class="me1">to_owned</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; port<span class="sy0">:</span> port<span class="sy0">,</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; hooks<span class="sy0">:</span> Vec<span class="sy0">::</span><span class="me2">new</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp;
&nbsp; &nbsp; pub fn add_events_hook<span class="sy0">&lt;</span>E<span class="sy0">:</span> Events <span class="sy0">+</span> <span class="st0">'static&gt;(&amp;mut self, hook: E) {</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp;self.hooks.push(Box::new(hook));</span>
<span class="st0"> &nbsp; &nbsp;}</span>
&nbsp;
<span class="st0"> &nbsp; &nbsp;pub fn get(&amp;self, endpoint: &amp;str) {</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp;let cmd = format!(&quot;GET {} HTTP/1.1<span class="es1">\r</span><span class="es1">\n</span>Host: {}<span class="es1">\r</span><span class="es1">\n</span><span class="es1">\r</span><span class="es1">\n</span>&quot;, endpoint, self.host).into_bytes();</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp;let mut socket = self.connect().unwrap();</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp;socket.write(cmd.as_slice()).unwrap();</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp;socket.flush().unwrap();</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp;for hook in &amp;self.hooks {</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;hook.on_pre_read();</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp;}</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp;loop {</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;let mut buf = vec![0; 512usize];</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;let cnt = socket.read(&amp;mut buf[..]).unwrap();</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;buf.truncate(cnt);</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if !buf.is_empty() {</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for hook in &amp;self.hooks {</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;hook.on_read(buf.as_slice());</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;} else {</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for hook in &amp;self.hooks {</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;hook.on_post_read();</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break;</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp;}</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp;for hook in &amp;self.hooks {</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;hook.on_shutdown();</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp;}</span>
&nbsp;
<span class="st0"> &nbsp; &nbsp;}</span>
&nbsp;
<span class="st0"> &nbsp; &nbsp;pub fn connect(&amp;self) -&gt; io::Result&lt;TcpStream&gt;{</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp;let addr = format!(&quot;{}:{}&quot;, self.host, self.port);</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp;match TcpStream::connect(addr) {</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Ok(stream) =&gt; {</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for hook in &amp;self.hooks {</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;hook.on_connect(&amp;self.host, self.port);</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Ok(stream)</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;},</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Err(error) =&gt; {</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for hook in &amp;self.hooks {</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;hook.on_error(error.description());</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Err(error)</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;},</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp;}</span>
&nbsp;
<span class="st0"> &nbsp; &nbsp;}</span>
<span class="st0">}</span></pre></td></tr></table></div></td></tr></tbody></table></div>Структура HttpClient имплементирует функцию add_events_hook которая используется для регистрации обработчика событий.<br />
Соберем все вместе в функции main, которая:<ul><li>инициализирует HttpClient</li>
<li>регистрирует Логгер как обработчик событий для HttpCliemt</li>
<li>Выполняет сетевые вызовы используя HttpClient. Результат вызовов попадают в события структуры Logger</li>
</ul><div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="579009327"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="579009327" style="height: 110px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
</pre></td><td class="de1"><pre class="de1">fn main<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; let mut &nbsp;http_stream <span class="sy0">=</span> HttpClient<span class="sy0">::</span><span class="me2">new</span><span class="br0">&#40;</span><span class="st0">&quot;httpbin.org&quot;</span><span class="sy0">,</span> <span class="nu0">80</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; http_stream.<span class="me1">add_events_hook</span><span class="br0">&#40;</span>Logger<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; http_stream.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&quot;/ip&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>В консоли результаты работы структуры Logger выгляди так:<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="423043496"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="423043496" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="de1"><pre class="de1">Connected to httpbin.org on port <span class="nu0">80</span>
Receiving content:
&nbsp;
HTTP<span class="sy0">/</span><span class="nu0">1.1</span> <span class="nu0">200</span> OK
Connection: keep-alive
Server: meinheld<span class="sy0">/</span>0.6.1
Date: Fri, 03 Nov <span class="nu0">2017</span> 09:<span class="nu0">16</span>:<span class="nu0">40</span> GMT
Content-Type: application<span class="sy0">/</span>json
Access-Control-Allow-Origin: <span class="sy0">*</span>
Access-Control-Allow-Credentials: <span class="kw2">true</span>
X-Powered-By: Flask
X-Processed-Time: <span class="nu0">0.000749111175537</span>
Content-Length: <span class="nu0">33</span>
Via: <span class="nu0">1.1</span> vegur
&nbsp;
<span class="br0">&#123;</span>
&nbsp; <span class="st0">&quot;origin&quot;</span>: <span class="st0">&quot;212.22.171.150&quot;</span>
<span class="br0">&#125;</span>
&nbsp;
Finished receiving content.
Connection closed.</pre></td></tr></table></div></td></tr></tbody></table></div>Код проекта вы можете найти <a rel="nofollow noopener noreferrer" href="https://gist.github.com/mattgathu/73712cb7399834d6f8162d641830cbb7" target="_blank" title="https://gist.github.com/mattgathu/73712cb7399834d6f8162d641830cbb7">здесь</a><br />
<br />
<b><font size="3">Сноски</font></b><br />
Событийно-управляемый подход довольно часто используется в Rust. Вот список наиболее интересных на мой взгляд проектов:<ul><li>mio(<a rel="nofollow noopener noreferrer" href="https://github.com/carllerche/mio" target="_blank" title="https://github.com/carllerche/mio">https://github.com/carllerche/mio</a>) - легковестная I/O бибилотека на Rust</li>
<li>ws-rs(<a rel="nofollow noopener noreferrer" href="https://github.com/housleyjk/ws-rs" target="_blank" title="https://github.com/housleyjk/ws-rs">https://github.com/housleyjk/ws-rs</a>) - легковестный веб-сокет на Rust</li>
<li>tokio-core(<a rel="nofollow noopener noreferrer" href="https://github.com/tokio-rs/tokio-core" target="_blank" title="https://github.com/tokio-rs/tokio-core">https://github.com/tokio-rs/tokio-core</a>) - I/O примитивы и событийный асинхронный цикл на Rust</li>
</ul><br />
<font size="3"><b>Ссылки</b></font><ol style="list-style-type: decimal"><li><a rel="nofollow noopener noreferrer" href="https://en.wikipedia.org/wiki/Observer_pattern" target="_blank" title="https://en.wikipedia.org/wiki/Observer_pattern">https://en.wikipedia.org/wiki/Observer_pattern</a></li>
<li><a rel="nofollow noopener noreferrer" href="https://en.wikipedia.org/wiki/Event-driven_programming" target="_blank" title="https://en.wikipedia.org/wiki/Event-driven_programming">https://en.wikipedia.org/wiki/... rogramming</a></li>
<li><a rel="nofollow noopener noreferrer" href="https://doc.rust-lang.org/book/second-edition/ch10-02-traits.html" target="_blank" title="https://doc.rust-lang.org/book/second-edition/ch10-02-traits.html">https://doc.rust-lang.org/book... raits.html</a></li>
<li><a rel="nofollow noopener noreferrer" href="https://doc.rust-lang.org/book/second-edition/ch19-03-advanced-traits.html" target="_blank" title="https://doc.rust-lang.org/book/second-edition/ch19-03-advanced-traits.html">https://doc.rust-lang.org/book... raits.html</a></li>
<li><a rel="nofollow noopener noreferrer" href="https://doc.rust-lang.org/std/net/struct.TcpStream.html" target="_blank" title="https://doc.rust-lang.org/std/net/struct.TcpStream.html">https://doc.rust-lang.org/std/... tream.html</a></li>
<li><a rel="nofollow noopener noreferrer" href="https://github.com/seanmonstar/reqwest/issues/155" target="_blank" title="https://github.com/seanmonstar/reqwest/issues/155">https://github.com/seanmonstar/reqwest/issues/155</a></li>
</ol><br />
<a rel="nofollow noopener noreferrer" href="https://mattgathu.github.io/simple-events-hook-rust/" target="_blank" title="https://mattgathu.github.io/simple-events-hook-rust/">Оригинал</a></div>

]]></content:encoded>
			<dc:creator>loothood</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/606805/5075.html</guid>
		</item>
		<item>
			<title>Пишем CHIP-8 эмулятор с использованием Rust и WebAssembly (часть 2)</title>
			<link>https://www.cyberforum.ru/blogs/606805/5071.html</link>
			<pubDate>Mon, 25 Dec 2017 20:11:43 GMT</pubDate>
			<description>_(Исходную статью я разбил на две части. Оригинал...</description>
			<content:encoded><![CDATA[<div><i><u>(Исходную статью я разбил на две части. <a rel="nofollow noopener noreferrer" href="http://blog.scottlogic.com/2017/12/13/chip8-emulator-webassembly-rust.html" target="_blank" title="http://blog.scottlogic.com/2017/12/13/chip8-emulator-webassembly-rust.html">Оригинал</a>)</u></i><br />
Первую часть перевода можно почитать <a href="https://www.cyberforum.ru/blogs/606805/blog5067.html">тут</a><br />
<font size="3"><b>Работа с памятью</b></font><br />
Создание интерфейса с помощью WebAssembly может быть довольно сложным. WebAssembly поддерживает только четыре базовых типа, поэтому передача чего-либо более сложного на границе WebAssembly/JavaScript требует некоторого кодирования/декодирования.<br />
<br />
WebAssembly и JavaScript работают с общей памятью, к которой оба имеют на чтение и изменение. Данные могут быть общими через общие ячейки памяти.<br />
<br />
Например, у эмулятора CHIP-8 всего 4Кб памяти, которая определена структурами и экспортируется следующим способом:<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="20589930"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="20589930" style="height: 206px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="de1"><pre class="de1"><span class="kw4">static</span> mut CPU<span class="sy0">:</span> Cpu <span class="sy0">=</span> Cpu <span class="br0">&#123;</span>
&nbsp; &nbsp; memory<span class="sy0">:</span> <span class="br0">&#91;</span><span class="nu0">0</span><span class="sy0">;</span> <span class="nu0">4096</span><span class="br0">&#93;</span><span class="sy0">,</span>
&nbsp; &nbsp; <span class="co1">// other fields go here …</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="co2">#[no_mangle]</span>
pub fn get_memory<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">-&gt;</span> <span class="sy0">&amp;</span><span class="st0">'static [u8; 4096] {</span>
<span class="st0"> &nbsp; &nbsp;unsafe {</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp;&amp;CPU.memory</span>
<span class="st0"> &nbsp; &nbsp;}</span>
<span class="st0">}</span></pre></td></tr></table></div></td></tr></tbody></table></div>Во время выполнения экземпляр CPU будет размещен где-то в памяти модуля WebAssembly. Мы можем узнать где именно, используя функцию get_memory.<br />
<br />
На стороне JavaScript, мы можем получить доступ к этой памяти с помощью exports.memory. С помощью функции get_memory, к 4Кб памяти CHIP-8 можно получить доступ так:<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="219686804"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="219686804" style="height: 158px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
</pre></td><td class="de1"><pre class="de1"><span class="kw4">const</span> instance <span class="sy0">=</span> await WebAssembly.<span class="me1">instantiate</span><span class="br0">&#40;</span>module<span class="br0">&#41;</span><span class="sy0">;</span>
<span class="kw4">const</span> exports <span class="sy0">=</span> instance.<span class="me1">exports</span><span class="sy0">;</span>
&nbsp;
<span class="kw4">const</span> programMemory <span class="sy0">=</span> new Uint8Array<span class="br0">&#40;</span>
&nbsp; exports.<span class="me1">memory</span>.<span class="me1">buffer</span><span class="sy0">,</span>
&nbsp; exports.<span class="me1">get_memory</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>
&nbsp; <span class="nu0">4096</span>
<span class="br0">&#41;</span><span class="sy0">;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Когда я запускаю код выше, get_memory возвращает значение 16760, в котором компилятор Rust решил выделить эту структуру.<br />
<br />
Загрузка ROM в память так же проста. Сброс CPU (сбрасывает регистры и т.д.), а затем происходит запись в массив programMemory:<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="955107739"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="955107739" style="height: 174px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
</pre></td><td class="de1"><pre class="de1">fetch<span class="br0">&#40;</span>`roms<span class="sy0">/</span>$<span class="br0">&#123;</span>rom<span class="br0">&#125;</span>`<span class="br0">&#41;</span>
&nbsp; .<span class="me1">then</span><span class="br0">&#40;</span>i <span class="sy0">=&gt;</span> i.<span class="me1">arrayBuffer</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; .<span class="me1">then</span><span class="br0">&#40;</span>buffer <span class="sy0">=&gt;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw4">const</span> rom <span class="sy0">=</span> new DataView<span class="br0">&#40;</span>buffer<span class="sy0">,</span> <span class="nu0">0</span><span class="sy0">,</span> buffer.<span class="me1">byteLength</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; exports.<span class="me1">reset</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>i <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span> i <span class="sy0">&lt;</span> rom.<span class="me1">byteLength</span><span class="sy0">;</span> i<span class="sy0">++</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; programMemory<span class="br0">&#91;</span><span class="nu12">0x200</span> <span class="sy0">+</span> i<span class="br0">&#93;</span> <span class="sy0">=</span> rom.<span class="me1">getUint8</span><span class="br0">&#40;</span>i<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Обратите внимание на смещение 0х200 - оно связано с загрузкой ROM с 512-байтовым смещением.<br />
<br />
Чтение дисплея или регистра значений использует тот же подход, что и выше.<br />
<br />
<br />
<font size="3"><b>Немного Rust</b></font><br />
Я новичок в Rust(около двух недель), потому я не привожу много своего кода. Боюсь показаться глупым из-за очевидных ошибок.<br />
<br />
Мой опыт использования Rust очень вдохновляет. Язык гораздо более строгий, чем те языки что я использовал до этого. Это другой конец палки, если сравнивать его с JavaScript. Кроме того, Rust современен и элегантен. По-моему, самая сложная концепция, к которой придется привыкнуть - это <a rel="nofollow noopener noreferrer" href="https://doc.rust-lang.org/book/first-edition/references-and-borrowing.html" target="_blank" title="https://doc.rust-lang.org/book/first-edition/references-and-borrowing.html">концепция владения Rust</a>. Я работал с несколькими методами управления памятью (сборщик мусора, автоматический подсчет ссылок), однако концепция владения Rust, где у вас есть единственное изменяемое связывание с ресурсом, нова для меня.<br />
<br />
Часть эмулятора CHIP-8, которая по-моему получилось особенно хорошо, это метод execute_opcode. Инструкции CHIP-8 имеют длину 16 бит, как описано в <a rel="nofollow noopener noreferrer" href="http://devernay.free.fr/hacks/chip8/C8TECH10.HTM#3.0" target="_blank" title="http://devernay.free.fr/hacks/chip8/C8TECH10.HTM#3.0">этой технической справочной информации</a>.<br />
<br />
Для некоторых инструкций первый полубайт (4 бита) представляет код операции, а остальные полубайты кодируют данные кода операции. Например, операция «jump» обновляют счетчик программы с определенным адресом. Он кодируется как 0x1nnn, где первое значение 0x1 кодирует операцию перехода, а следующие три(nnn) - представляют адрес.<br />
<br />
Сопоставление шаблонов с диапазонами в Rust - идеальный инструмент для реализации этого. Вот пример, который использует соответствие диапазонов для реализации инструкции перехода:<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="196309428"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="196309428" style="height: 142px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
</pre></td><td class="de1"><pre class="de1">fn process_opcode<span class="br0">&#40;</span><span class="sy0">&amp;</span>mut self<span class="sy0">,</span> opcode<span class="sy0">:</span> u16<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; match <span class="br0">&#40;</span>opcode<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="nu12">0x1000</span> ... <span class="nu12">0x1FFF</span> <span class="sy0">=&gt;</span> self.<span class="me1">pc</span> <span class="sy0">=</span> opcode <span class="sy0">&amp;</span> <span class="nu12">0x0FFF</span><span class="sy0">,</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// match other ranges to process other opcodes.</span>
&nbsp; &nbsp; &nbsp; &nbsp; _ <span class="sy0">=&gt;</span> <span class="br0">&#40;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>К сожалению, не все инструкции могут быть разделены на основе первого полубайта. Например, есть девять различных инструкций, начинающихся с 0x8, что приводит к вложенному сопоставлению:<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="824367054"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="824367054" style="height: 286px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="de1"><pre class="de1">fn process_opcode<span class="br0">&#40;</span><span class="sy0">&amp;</span>mut self<span class="sy0">,</span> opcode<span class="sy0">:</span> u16<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; match <span class="br0">&#40;</span>opcode<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="nu12">0x1000</span> ... <span class="nu12">0x1FFF</span> <span class="sy0">=&gt;</span> self.<span class="me1">pc</span> <span class="sy0">=</span> opcode <span class="sy0">&amp;</span> <span class="nu12">0x0FFF</span><span class="sy0">,</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// ...</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="nu12">0x8000</span> ... <span class="nu12">0x8FFF</span> <span class="sy0">=&gt;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; match opcode <span class="sy0">&amp;</span> <span class="nu12">0x00F</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// LD Vx, Vy</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="nu12">0x0</span> <span class="sy0">=&gt;</span> self.<span class="me1">v</span><span class="br0">&#91;</span>x<span class="br0">&#93;</span> <span class="sy0">=</span> self.<span class="me1">v</span><span class="br0">&#91;</span>y<span class="br0">&#93;</span><span class="sy0">,</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// OR Vx, Vy</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="nu12">0x1</span> <span class="sy0">=&gt;</span> self.<span class="me1">v</span><span class="br0">&#91;</span>x<span class="br0">&#93;</span> <span class="sy0">=</span> self.<span class="me1">v</span><span class="br0">&#91;</span>x<span class="br0">&#93;</span> <span class="sy0">|</span> self.<span class="me1">v</span><span class="br0">&#91;</span>y<span class="br0">&#93;</span><span class="sy0">,</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// …</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#125;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// ...</span>
&nbsp; &nbsp; &nbsp; &nbsp; _ <span class="sy0">=&gt;</span> <span class="br0">&#40;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Итак, чтобы обработать инструкции, мы должны иметь возможность сопоставлять коды в разных местах. С Rust это возможно, создавая кортеж, который разбивает код операции на четыре полубайта, а затем сопоставляя эти компоненты отдельно. Ниже приведен пример некоторых команд:<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="347241870"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="347241870" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="de1"><pre class="de1"><span class="co1">// break up into nibbles</span>
let op_1 <span class="sy0">=</span> <span class="br0">&#40;</span>opcode <span class="sy0">&amp;</span> <span class="nu12">0xF000</span><span class="br0">&#41;</span> <span class="sy0">&gt;&gt;</span> <span class="nu0">12</span><span class="sy0">;</span>
let op_2 <span class="sy0">=</span> <span class="br0">&#40;</span>opcode <span class="sy0">&amp;</span> <span class="nu12">0x0F00</span><span class="br0">&#41;</span> <span class="sy0">&gt;&gt;</span> <span class="nu0">8</span><span class="sy0">;</span>
let op_3 <span class="sy0">=</span> <span class="br0">&#40;</span>opcode <span class="sy0">&amp;</span> <span class="nu12">0x00F0</span><span class="br0">&#41;</span> <span class="sy0">&gt;&gt;</span> <span class="nu0">4</span><span class="sy0">;</span>
let op_4 <span class="sy0">=</span> opcode <span class="sy0">&amp;</span> <span class="nu12">0x000F</span><span class="sy0">;</span>
&nbsp;
match <span class="br0">&#40;</span>op_1<span class="sy0">,</span> op_2<span class="sy0">,</span> op_3<span class="sy0">,</span> op_4<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="co1">// CLS</span>
&nbsp; &nbsp; <span class="br0">&#40;</span><span class="nu0">0</span><span class="sy0">,</span> <span class="nu0">0</span><span class="sy0">,</span> <span class="nu12">0xE</span><span class="sy0">,</span> <span class="nu0">0</span><span class="br0">&#41;</span> <span class="sy0">=&gt;</span> self.<span class="me1">display</span>.<span class="me1">cls</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>
&nbsp; &nbsp; <span class="co1">// JP</span>
&nbsp; &nbsp; <span class="br0">&#40;</span><span class="nu12">0x1</span><span class="sy0">,</span> _<span class="sy0">,</span> _<span class="sy0">,</span> _<span class="br0">&#41;</span> <span class="sy0">=&gt;</span> self.<span class="me1">pc</span> <span class="sy0">=</span> nnn<span class="sy0">,</span>
&nbsp; &nbsp; <span class="co1">// LD Vx, Vy</span>
&nbsp; &nbsp; <span class="br0">&#40;</span><span class="nu12">0x8</span><span class="sy0">,</span> _<span class="sy0">,</span> _<span class="sy0">,</span> <span class="nu12">0x0</span><span class="br0">&#41;</span> <span class="sy0">=&gt;</span> self.<span class="me1">v</span><span class="br0">&#91;</span>x<span class="br0">&#93;</span> <span class="sy0">=</span> self.<span class="me1">v</span><span class="br0">&#91;</span>y<span class="br0">&#93;</span><span class="sy0">,</span>
&nbsp; &nbsp; <span class="co1">// OR Vx, Vy</span>
&nbsp; &nbsp; <span class="br0">&#40;</span><span class="nu12">0x8</span><span class="sy0">,</span> _<span class="sy0">,</span> _<span class="sy0">,</span> <span class="nu12">0x1</span><span class="br0">&#41;</span> <span class="sy0">=&gt;</span> self.<span class="me1">v</span><span class="br0">&#91;</span>x<span class="br0">&#93;</span> <span class="sy0">=</span> self.<span class="me1">v</span><span class="br0">&#91;</span>x<span class="br0">&#93;</span> <span class="sy0">|</span> self.<span class="me1">v</span><span class="br0">&#91;</span>y<span class="br0">&#93;</span><span class="sy0">,</span>
&nbsp; &nbsp; <span class="co1">// AND Vx, Vy</span>
&nbsp; &nbsp; <span class="br0">&#40;</span><span class="nu12">0x8</span><span class="sy0">,</span> _<span class="sy0">,</span> _<span class="sy0">,</span> <span class="nu12">0x2</span><span class="br0">&#41;</span> <span class="sy0">=&gt;</span> self.<span class="me1">v</span><span class="br0">&#91;</span>x<span class="br0">&#93;</span> <span class="sy0">=</span> self.<span class="me1">v</span><span class="br0">&#91;</span>x<span class="br0">&#93;</span> <span class="sy0">&amp;</span> self.<span class="me1">v</span><span class="br0">&#91;</span>y<span class="br0">&#93;</span><span class="sy0">,</span>
&nbsp; &nbsp; <span class="co1">// LD F, Vx</span>
&nbsp; &nbsp; <span class="br0">&#40;</span><span class="nu12">0xF</span><span class="sy0">,</span> _<span class="sy0">,</span> <span class="nu12">0x2</span><span class="sy0">,</span> <span class="nu12">0x9</span><span class="br0">&#41;</span> <span class="sy0">=&gt;</span> self.<span class="me1">i</span> <span class="sy0">=</span> vx as u16 <span class="sy0">*</span> <span class="nu0">5</span><span class="sy0">,</span>
&nbsp; &nbsp; <span class="co1">// ...</span>
&nbsp; &nbsp; <span class="br0">&#40;</span>_<span class="sy0">,</span> _<span class="sy0">,</span> _<span class="sy0">,</span> _<span class="br0">&#41;</span> <span class="sy0">=&gt;</span> <span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Заметьте, я мог бы использовать деструктуризацию, чтобы вытащить другие компоненты каждой команды, например:<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="279436677"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="279436677" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="nu12">0x8</span><span class="sy0">,</span> x<span class="sy0">,</span> y<span class="sy0">,</span> <span class="nu12">0x0</span><span class="br0">&#41;</span> <span class="sy0">=&gt;</span> self.<span class="me1">v</span><span class="br0">&#91;</span>x as usize<span class="br0">&#93;</span> <span class="sy0">=</span> self.<span class="me1">v</span><span class="br0">&#91;</span>y as usize<span class="br0">&#93;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Однако, данный подход может осложнить код, потому я извлекаю большинство типичных шаблонов кода операций перед выражением соответствия:<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="46921933"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="46921933" style="height: 142px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
</pre></td><td class="de1"><pre class="de1">let x <span class="sy0">=</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>opcode <span class="sy0">&amp;</span> <span class="nu12">0x0F00</span><span class="br0">&#41;</span> <span class="sy0">&gt;&gt;</span> <span class="nu0">8</span><span class="br0">&#41;</span> as usize<span class="sy0">;</span>
let y <span class="sy0">=</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>opcode <span class="sy0">&amp;</span> <span class="nu12">0x00F0</span><span class="br0">&#41;</span> <span class="sy0">&gt;&gt;</span> <span class="nu0">4</span><span class="br0">&#41;</span> as usize<span class="sy0">;</span>
let vx <span class="sy0">=</span> self.<span class="me1">v</span><span class="br0">&#91;</span>x<span class="br0">&#93;</span><span class="sy0">;</span>
let vy <span class="sy0">=</span> self.<span class="me1">v</span><span class="br0">&#91;</span>y<span class="br0">&#93;</span><span class="sy0">;</span>
let nnn <span class="sy0">=</span> opcode <span class="sy0">&amp;</span> <span class="nu12">0x0FFF</span><span class="sy0">;</span>
let kk <span class="sy0">=</span> <span class="br0">&#40;</span>opcode <span class="sy0">&amp;</span> <span class="nu12">0x00FF</span><span class="br0">&#41;</span> as u8<span class="sy0">;</span>
let n <span class="sy0">=</span> <span class="br0">&#40;</span>opcode <span class="sy0">&amp;</span> <span class="nu12">0x000F</span><span class="br0">&#41;</span> as u8<span class="sy0">;</span></pre></td></tr></table></div></td></tr></tbody></table></div><br />
<font size="3"><b>Управление зависимостями</b></font><br />
Rust упаковывает в пакет(crates) повторно используемые компоненты, которыми управляет cargo. Это очень похоже на npm, CocoaPods и другие менеджеры пакетов.<br />
<br />
В моем проекте было несколько пакетов(crates), которые полезны для использования: - <a rel="nofollow noopener noreferrer" href="https://crates.io/crates/rand" target="_blank" title="https://crates.io/crates/rand">rand</a>- генерация случайных чисел. - <a rel="nofollow noopener noreferrer" href="https://crates.io/crates/lazy_static" target="_blank" title="https://crates.io/crates/lazy_static">lazy_static</a> - в Rust вы не можете вызвать функцию, чтобы построить статическое значение, поэтому вы не можете использовать функцию-конструктор. Ленивый статический макрос позволяет вам инициализировать статические переменные лениво, избегая этого ограничения.<br />
<br />
К сожалению, я столкнулся с трудностями при интеграции этих пакетов в мой проект. Пакеты имеют зависимость от платформы, потому их пришлось доработать чтобы подружить их с WebAssembly. Я нашел <a rel="nofollow noopener noreferrer" href="https://github.com/aochagavia/rand/commit/cbd99e5e8822018f028464927dac13beb4007bf6#diff-6c5562ff49c639e4938ea91f26a67e56R547" target="_blank" title="https://github.com/aochagavia/rand/commit/cbd99e5e8822018f028464927dac13beb4007bf6#diff-6c5562ff49c639e4938ea91f26a67e56R547">форк с некоторыми необходимыми изменениями</a>, но изменения не все, которые были мне необходимы.<br />
<br />
В моем случае, я просто взял реализацию случайных чисел и скопировал в ской код и отказался от ленивой инициализации.<br />
<br />
<br />
<font size="3"><b>Заключение</b></font><br />
Я в самом деле впечатлен языком Rust. Уверен что WebAssembly - отличная возможность по привлечению программистов для этого языка. В краткосрочной перспективе выбор языка для WebAssembly немного ограничен. Для веб разработчиков, которые хотят попробовать что-то новое, Rust выглядит как самый лучший вариант на данный момент.<br />
<a rel="nofollow noopener noreferrer" href="https://github.com/ColinEberhardt/wasm-rust-chip8" target="_blank" title="https://github.com/ColinEberhardt/wasm-rust-chip8"><br />
Код проекта на гитхаб</a></div>

]]></content:encoded>
			<dc:creator>loothood</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/606805/5071.html</guid>
		</item>
		<item>
			<title>Пишем CHIP-8 эмулятор с использованием Rust и WebAssembly</title>
			<link>https://www.cyberforum.ru/blogs/606805/5067.html</link>
			<pubDate>Sun, 24 Dec 2017 23:04:24 GMT</pubDate>
			<description>_(Исходную статью я разбил на две части. Перевод второй части будет позже. Оригинал...</description>
			<content:encoded><![CDATA[<div><i><u>(Исходную статью я разбил на две части. Перевод второй части будет позже. <a rel="nofollow noopener noreferrer" href="http://blog.scottlogic.com/2017/12/13/chip8-emulator-webassembly-rust.html" target="_blank" title="http://blog.scottlogic.com/2017/12/13/chip8-emulator-webassembly-rust.html">Оригинал</a>)</u></i><br />
Последние несколько месяцев я исследовал потенциал Webassembly. Особое внимание я уделил <a rel="nofollow noopener noreferrer" href="http://blog.scottlogic.com/2017/10/17/wasm-mandelbrot.html" target="_blank" title="http://blog.scottlogic.com/2017/10/17/wasm-mandelbrot.html">параметрам компиляции и производительности</a>, недавно обратил внимание на <a rel="nofollow noopener noreferrer" href="http://blog.scottlogic.com/2017/10/30/migrating-d3-force-layout-to-webassembly.html" target="_blank" title="http://blog.scottlogic.com/2017/10/30/migrating-d3-force-layout-to-webassembly.html">D3 Force Layout в WebAssembly с использованием AssemblyScript</a>.<br />
<br />
Я хотел попробовать свои силы в создании сложного приложения WebAssembly, поэтому я проводил вечера, работая над эмулятором CHIP-8 ... и изучая Rust!<br />
<br />
Вы можете найти код завершенного эмулятора на <a rel="nofollow noopener noreferrer" href="https://github.com/ColinEberhardt/wasm-rust-chip8" target="_blank" title="https://github.com/ColinEberhardt/wasm-rust-chip8">GitHub</a>. Так же, эмулятор размещен <a rel="nofollow noopener noreferrer" href="https://colineberhardt.github.io/wasm-rust-chip8/web/" target="_blank" title="https://colineberhardt.github.io/wasm-rust-chip8/web/">онлайн</a>, если вы хотите поиграть с ним(я бы порекомендовал Kraftwerk’s Computer Love как музыку на фоне).<br />
<br />
<br />
<b><font size="3">Почему Rust?</font></b><br />
На данный момент, есть <a rel="nofollow noopener noreferrer" href="https://stackoverflow.com/questions/43540878/what-languages-can-be-compiled-to-web-assembly-or-wasm" target="_blank" title="https://stackoverflow.com/questions/43540878/what-languages-can-be-compiled-to-web-assembly-or-wasm">несколько языков с поддержкой WebAssembly</a>. Поддержка их несколько сыра. Сейчас, в WebAssembly нет сборщика мусора(GC), в результате языки, которые не требуют GC, имеют лучшую поддержку. Самая зрелая поддержка C/C++ через Emscripten, но, если быть абсолютно честным, мне не очень нравится C++ ... или Emscripten!<br />
<br />
Rust - относительно новый язык (2010), который, будучи синтаксически подобным C++, разработан, чтобы быть более «безопасным». Он также имеет множество языковых особенностей, общих с другими современными языками программирования, такими как Swift. Все вышеперечисленное, в сочетании с активным сообществом, внесло свой вклад в достижение титула <a rel="nofollow noopener noreferrer" href="https://medium.com/mozilla-tech/why-rust-is-the-most-loved-language-by-developers-666add782563" target="_blank" title="https://medium.com/mozilla-tech/why-rust-is-the-most-loved-language-by-developers-666add782563">«Самый любимый язык»</a>.<br />
<br />
Итак, для моего эмулятора CHIP-8 мне нужен язык с относительно зрелой поддержкой WebAssembly, который не создает раздутые двоичные файлы (т.е. нет GC и минимальное время выполнения).<br />
<br />
Rust был очевидным выбором.<br />
<br />
Я не буду подробно рассказывать о своей реализации CHIP-8, однако я выделил несколько областей, в которых были отмечены особенности языка Rust.<br />
<br />
Но сначала, что такое CHIP-8?<br />
<br />
<br />
<b><font size="3">CHIP-8</font></b><br />
Должен признаться, эмулятор давно был в моем списке &quot;сделать&quot; (<i>я бы написал &quot;todo список&quot;, но не был уверен что будет понятно - примечание переводчика</i>). Я начинал программировать на 8-битных микрокомпьютерах, и мне всегда нравилось писать низкоуровневый код. Моя первоначальная идея заключалась в том, чтобы написать эмулятор Atari 2600 VCS, потому что <a rel="nofollow noopener noreferrer" href="https://www.amazon.co.uk/Racing-Beam-Computer-Platform-Studies/dp/026201257X" target="_blank" title="https://www.amazon.co.uk/Racing-Beam-Computer-Platform-Studies/dp/026201257X">его архитектура просто невероятна</a>. Однако, чтобы эмулировать данную архитектуру, надо немало постараться. Возможно, стоит начать с чего попроще?<br />
<br />
Немного почитав, я узнал о <a rel="nofollow noopener noreferrer" href="https://en.wikipedia.org/wiki/CHIP-8" target="_blank" title="https://en.wikipedia.org/wiki/CHIP-8">CHIP-8</a>. Его архитектура является достаточно простой для эмуляции из-за относительно простого набора команд. Интересно, что CHIP-8 - это виртуальная машина, которая была реализована на ряде компьютеров 1970х и калькуляторах 1980х. Вы можете почитать побольше о CHIP-8 и преимуществе интерпретаторов <a rel="nofollow noopener noreferrer" href="https://archive.org/stream/byte-magazine-1978-12/1978_12_BYTE_03-12_Life#page/n109/mode/2up" target="_blank" title="https://archive.org/stream/byte-magazine-1978-12/1978_12_BYTE_03-12_Life#page/n109/mode/2up">в этом блоге</a>.<br />
<br />
Вкратце, у CHIP-8 4Кб оперативной памяти. Первые 512 байт используются интерпретаторами машинного перевода (да, всего 512 байт!). Это 16 8-битовых регистров и один 16-ти разрядный программный регистр. В архитектуре есть стек, который может хранить до 16 адресов, что позволяет поддерживать операции «call», а также «jump». CPU поддерживает 35 различных кодов операций (то есть инструкций), которые имеют ширину всего 2 байта. Для периферийных устройств CHIP-8 имеет простой дисплей размером 64x32 пикселя, базовую поддержку звука и клавиатуру с 16 клавишами.<br />
<br />
Помимо прочего, CHIP-8 является относительно простым, похоже, не является проприетарным, и, как результат, <a rel="nofollow noopener noreferrer" href="http://devernay.free.fr/hacks/chip8/C8TECH10.HTM" target="_blank" title="http://devernay.free.fr/hacks/chip8/C8TECH10.HTM">технические справочные материалы легко доступны</a>.<br />
<br />
Если вы заинтересовались CHIP-8, я настоятельно рекомендую <a rel="nofollow noopener noreferrer" href="http://www.multigesture.net/articles/how-to-write-an-emulator-chip-8-interpreter/" target="_blank" title="http://www.multigesture.net/articles/how-to-write-an-emulator-chip-8-interpreter/">статьи Лоуренса Мюллера</a>, в которых в деталях рассказано о многих аспектах CHIP-8. В данной же статье, я хотел бы сделать упор на Rust и WebAssembly.<br />
<br />
<br />
<b><font size="3">Rust и WebAssembly</font></b><br />
Поддержка Rust для WebAssembly быстро развилась за последние несколько месяцев. Первоначально поддержка зависела от Emscripten и «fastcomp» fork LLVM, однако это приводит к довольно долгому времени выполнения готовой программы и большому размеру бинарных файлов. <br />
<br />
Совсем недавно в Rust была добавлена поддержка wasm-unknown-unknown, благодаря этому стало возможно убрать поддержку Emscripten, используя LLVM как бэкэнд напрямую. Это позволяет скомпилировать очень легковесные бинарники. Но нет пределов совершенству, потому команда Rust создала <a rel="nofollow noopener noreferrer" href="https://github.com/alexcrichton/wasm-gc" target="_blank" title="https://github.com/alexcrichton/wasm-gc">wasm-gc</a> для обработки сообщений wasm-файлов для удаления неиспользуемого кода.<br />
<br />
Благодаря этому обновлению, создание wasm модуля выглядит очень просто (<a rel="nofollow noopener noreferrer" href="https://www.hellorust.com/setup/wasm-target/" target="_blank" title="https://www.hellorust.com/setup/wasm-target/">сюда если вам нужен детальный гайд</a>). Следующий вызов cargo создаст wasm модуль:<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="282057410"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="282057410" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">cargo +nightly build <span class="re5">--release</span> <span class="re5">--target</span> wasm32-unknown-unknown</pre></td></tr></table></div></td></tr></tbody></table></div><i><u>Заметка: cargo в Rust это менеджер пакетов и инструмент сборки. cargo позволяет подключать зависимости(crates) и запускать билды или тесты.</u></i><br />
<br />
<br />
<b><font size="3">Структура эмулятора</font></b><br />
Ядром эмулятора является процессор, который реализуется как структура. Поля этой структуры почти полностью совпадают с архитектурой CHIP-8, состоящей из памяти, регистров, счетчика программ и т.д.<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="715668171"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="715668171" style="height: 334px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="de1"><pre class="de1">pub <span class="kw4">struct</span> Cpu <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="co1">// index register</span>
&nbsp; &nbsp; pub i<span class="sy0">:</span> u16<span class="sy0">,</span>
&nbsp; &nbsp; <span class="co1">// program counter</span>
&nbsp; &nbsp; pub pc<span class="sy0">:</span> u16<span class="sy0">,</span>
&nbsp; &nbsp; <span class="co1">// memory</span>
&nbsp; &nbsp; pub memory<span class="sy0">:</span> <span class="br0">&#91;</span>u8<span class="sy0">;</span> <span class="nu0">4096</span><span class="br0">&#93;</span><span class="sy0">,</span>
&nbsp; &nbsp; <span class="co1">// registers</span>
&nbsp; &nbsp; pub v<span class="sy0">:</span> <span class="br0">&#91;</span>u8<span class="sy0">;</span> <span class="nu0">16</span><span class="br0">&#93;</span><span class="sy0">,</span>
&nbsp; &nbsp; <span class="co1">// peripherals</span>
&nbsp; &nbsp; pub keypad<span class="sy0">:</span> Keypad<span class="sy0">,</span>
&nbsp; &nbsp; pub display<span class="sy0">:</span> Display<span class="sy0">,</span>
&nbsp; &nbsp; <span class="co1">// stack</span>
&nbsp; &nbsp; pub stack<span class="sy0">:</span> <span class="br0">&#91;</span>u16<span class="sy0">;</span> <span class="nu0">16</span><span class="br0">&#93;</span><span class="sy0">,</span>
&nbsp; &nbsp; <span class="co1">// stack pointer</span>
&nbsp; &nbsp; pub sp<span class="sy0">:</span> u8<span class="sy0">,</span>
&nbsp; &nbsp; <span class="co1">// delay timer</span>
&nbsp; &nbsp; pub dt<span class="sy0">:</span> u8
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Клавиатура и дисплей представляют собой отдельные структуры, которые управляют этими периферийными устройствами.<br />
<br />
Цикл выполнения процессора CHIP-8 довольно прост.<br />
<br />
В моей реализации CPU состоит из открытого метода execute_cycle, который считывает код операции из текущей ячейки памяти и обрабатывает ее:<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="326152928"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="326152928" style="height: 270px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="de1"><pre class="de1">fn read_word<span class="br0">&#40;</span>memory<span class="sy0">:</span> <span class="br0">&#91;</span>u8<span class="sy0">;</span> <span class="nu0">4096</span><span class="br0">&#93;</span><span class="sy0">,</span> index<span class="sy0">:</span> u16<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> u16 <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="br0">&#40;</span>memory<span class="br0">&#91;</span>index as usize<span class="br0">&#93;</span> as u16<span class="br0">&#41;</span> <span class="sy0">&lt;&lt;</span> <span class="nu0">8</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">|</span> <span class="br0">&#40;</span>memory<span class="br0">&#91;</span><span class="br0">&#40;</span>index <span class="sy0">+</span> <span class="nu0">1</span><span class="br0">&#41;</span> as usize<span class="br0">&#93;</span> as u16<span class="br0">&#41;</span>
<span class="br0">&#125;</span>
&nbsp;
impl Cpu <span class="br0">&#123;</span>
&nbsp; &nbsp; pub fn execute_cycle<span class="br0">&#40;</span><span class="sy0">&amp;</span>mut self<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; let opcode<span class="sy0">:</span> u16 <span class="sy0">=</span> read_word<span class="br0">&#40;</span>self.<span class="me1">memory</span><span class="sy0">,</span> self.<span class="me1">pc</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; self.<span class="me1">process_opcode</span><span class="br0">&#40;</span>opcode<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp;
&nbsp; &nbsp; fn process_opcode<span class="br0">&#40;</span><span class="sy0">&amp;</span>mut self<span class="sy0">,</span> opcode<span class="sy0">:</span> u16<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; ...
&nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Каждая инструкция, которая представляет собой два байта, интерпретируется методом process_opcode, о котором будет речь ниже.<br />
<br />
На основе кода операции, CPU может обновлять регистры, рисовать на дисплее, читать ввод с клавиатуры, выполнять другие операции.<br />
<br />
Ядро этой реализации, которая состоит из CPU, Display и Keypad, совпадает с большинством других реализаций Rust, которые вы найдете на GitHub и в других местах. Здесь нет ничего особенного, завязанного на WebAssembly!<br />
<br />
Мы хотим, чтобы жизненный цикл CPU был таким же, как у модуля WebAssembly, поэтому имеет смысл задать его глобальным статическим значением:<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="288109846"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="288109846" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1"><span class="kw4">static</span> mut CPU<span class="sy0">:</span> Cpu <span class="sy0">=</span> Cpu <span class="br0">&#123;</span>
&nbsp; &nbsp;<span class="co1">// Default field values added here</span>
<span class="br0">&#125;</span><span class="sy0">;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Чтобы позволить хостинговому JavaScript-коду взаимодействовать с этим статическим экземпляром, определим ряд общедоступных глобальных функций:<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="144615451"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="144615451" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="de1"><pre class="de1"><span class="co2">#[no_mangle]</span>
pub fn execute_cycle<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; unsafe <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; CPU.<span class="me1">execute_cycle</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="co2">#[no_mangle]</span>
pub fn get_memory<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">-&gt;</span> <span class="sy0">&amp;</span><span class="st0">'static [u8; 4096] {</span>
<span class="st0"> &nbsp; &nbsp;unsafe {</span>
<span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp;&amp;CPU.memory</span>
<span class="st0"> &nbsp; &nbsp;}</span>
<span class="st0">}</span>
&nbsp;
<span class="st0">#[no_mangle]</span>
<span class="st0">pub fn get_display() -&gt; &amp;'</span><span class="kw4">static</span> <span class="br0">&#91;</span>u8<span class="sy0">;</span> <span class="nu0">2048</span><span class="br0">&#93;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; unsafe <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">&amp;</span>CPU.<span class="me1">display</span>.<span class="me1">memory</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Атрибут no_mangle отключает <a rel="nofollow noopener noreferrer" href="https://en.wikipedia.org/wiki/Name_mangling" target="_blank" title="https://en.wikipedia.org/wiki/Name_mangling">редактирование имен</a>, гарантируя, что эти функции сохранят свои имена и могут быть вызваны извне.<br />
<br />
Эти глобальные функции создают простой API, который позволяет JavaScript-коду взаимодействовать с модулем WebAssembly. После того, как модуль WebAssembly извлечен, скомпилирован и создан, цикл requestAnimationFrame (rAF) используется для многократного вызова функции execute_cycle:<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="489937088"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="489937088" style="height: 286px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="de1"><pre class="de1"><span class="kw4">const</span> res <span class="sy0">=</span> await fetch<span class="br0">&#40;</span><span class="st0">&quot;chip8.wasm&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="kw4">const</span> buffer <span class="sy0">=</span> await res.<span class="me1">arrayBuffer</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="kw4">const</span> module <span class="sy0">=</span> await WebAssembly.<span class="me1">compile</span><span class="br0">&#40;</span>buffer<span class="br0">&#41;</span><span class="sy0">;</span>
<span class="kw4">const</span> instance <span class="sy0">=</span> await WebAssembly.<span class="me1">instantiate</span><span class="br0">&#40;</span>module<span class="br0">&#41;</span><span class="sy0">;</span>
<span class="kw4">const</span> exports <span class="sy0">=</span> instance.<span class="me1">exports</span><span class="sy0">;</span>
&nbsp;
<span class="kw4">const</span> runloop <span class="sy0">=</span> <span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">=&gt;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>var i <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span> i <span class="sy0">&lt;</span> <span class="nu0">10</span><span class="sy0">;</span> i<span class="sy0">++</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; exports.<span class="me1">execute_cycle</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; <span class="br0">&#125;</span>
&nbsp; exports.<span class="me1">decrement_timers</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; updateUI<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; window.<span class="me1">requestAnimationFrame</span><span class="br0">&#40;</span>runloop<span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span><span class="sy0">;</span>
window.<span class="me1">requestAnimationFrame</span><span class="br0">&#40;</span>runloop<span class="br0">&#41;</span><span class="sy0">;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Заметьте, что в каждом rAF цикле, функция execute_cycle вызывается 10 раз.<br />
<br />
Эмулятор CHIP-8 имеет тактовую частоту около 500 Гц, поэтому при вызове runloop со скоростью около 60 кадров в секунду это дает правильную скорость. Цикл также уменьшает таймер задержки CHIP-8, который работает на частоте 60 Гц.</div>

]]></content:encoded>
			<dc:creator>loothood</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/606805/5067.html</guid>
		</item>
		<item>
			<title>Пятничный Elm (Часть VII)</title>
			<link>https://www.cyberforum.ru/blogs/606805/4105.html</link>
			<pubDate>Fri, 29 Jan 2016 14:33:41 GMT</pubDate>
			<description>Пятничный Elm. Списки (Часть VII) 
 
 
Списки - одна из основных структур данных в Elm. В Elm есть...</description>
			<content:encoded><![CDATA[<div><font size="4">Пятничный Elm. Списки (Часть VII)</font><br />
<br />
<br />
Списки - одна из основных структур данных в Elm. В Elm есть синтаксическая поддержка списков, а <a rel="nofollow noopener noreferrer" href="http://package.elm-lang.org/packages/elm-lang/core/3.0.0/List" target="_blank" title="http://package.elm-lang.org/packages/elm-lang/core/3.0.0/List">модуль ядра для работы со списками</a> имеет все необходимые функции, которые можно ожидать в функциональном языке программирования. В данной заметке мы рассмотрим списки, а так же некоторые функции для работы  сними.<br />
<br />
<font size="3">О серии &quot;Пятничный Elm&quot;</font><br />
<br />
Это седьмой пост серии заметок о языке программирования Elm.<br />
Цель данной серии - дать читателям знания от уровня &quot;Что такое Elm&quot; до &quot;Гуру Elm&quot;, шаг за шагом.<br />
<br />
<br />
<font size="3">elm-repl</font><br />
<br />
Отличный способ посмотреть в действии код приведенный в заметке - elm repl (read-eval-print-loop (пер.: или по-русски «считать-выполнить-вывести на экран, повторить»)). Эта утилита устанавливается в системе вместе с elm. Просто наберите <font color="Red">elm-repl</font> в командной строке. Вы должны увидеть что-то похожее на это:<br />
<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="566248630"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="566248630" style="height: 110px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
</pre></td><td class="de1"><pre class="de1">elm-repl
<span class="re5">----</span> elm repl 0.16.0 <span class="re5">-----------------------------------------------------------</span>
&nbsp;:help <span class="kw1">for</span> <span class="kw3">help</span>, :exit to <span class="kw3">exit</span>, <span class="kw2">more</span> at
<span class="re5">--------------------------------------------------------------------------------</span>
<span class="sy0">&gt;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Теперь, введя любое Elm выражение, вы сможете сразу получить результат. В repl довольно сложно разрабатывать что-то серьезное, но чтобы поиграть с основами языка, он подходит идеально. Попробуйте любой код который будет в этой статье ввести в repl. Давайте начнем!<br />
<br />
<br />
<font size="3">Создание списков</font><br />
<br />
Есть несколько способов создания списков в Elm. Наиболее простой - записать элементы, разделенные запятыми, в квадратных скобках:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="546271278"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="546271278" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">aList <span class="sy0">=</span> <span class="br0">&#91;</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="nu0">3</span>, <span class="nu0">4</span><span class="br0">&#93;</span></pre></td></tr></table></div></td></tr></tbody></table></div><div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="908352132"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="908352132" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1">Result<span class="sy0">:</span>
<span class="br0">&#91;</span><span class="nu0">1</span>,<span class="nu0">2</span>,<span class="nu0">3</span>,<span class="nu0">4</span><span class="br0">&#93;</span> <span class="sy0">:</span> List number</pre></td></tr></table></div></td></tr></tbody></table></div>Очень похоже на массивы в C-подобных языках, но списки в Elm не поддерживают позиционный доступ (оригинал: positional access)  (вы не сможете прочитать\изменить\установить элемент по его порядковому номеру). В Elm есть модуль массивов - <a rel="nofollow noopener noreferrer" href="http://package.elm-lang.org/packages/elm-lang/core/3.0.0/Array" target="_blank" title="http://package.elm-lang.org/packages/elm-lang/core/3.0.0/Array">Array</a>, в котором поддерживается позиционный доступ. Но только списки поддерживаются синтаксически, да и работать в основном вы будете со списками.<br />
<br />
Как упоминалось в <a href="https://www.cyberforum.ru/blogs/606805/blog4100.html">прошлой</a> статье, тип списка всегда содержит тип его элементов. Поэтому REPL вывел тип <font color="red">List number</font> (так же, к этой функции, вы можете написать такую аннотацию: <font color="red">List Int </font> - <font color="red">number</font> это надтип <font color="red">Int</font>).<br />
<br />
Конечно же, вы можете создавать списки любых типов, а не только примитивных, таких как Int. Правило одно - все элементы списка имеют одинаковый тип. Вот пример списка кортежей:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="253226958"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="253226958" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#91;</span><span class="br0">&#40;</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="st0">&quot;three&quot;</span><span class="br0">&#41;</span>, <span class="br0">&#40;</span><span class="nu0">4</span>, <span class="nu0">5</span>, <span class="st0">&quot;six&quot;</span><span class="br0">&#41;</span>, <span class="br0">&#40;</span><span class="nu0">7</span>, <span class="nu0">8</span>, <span class="st0">&quot;nine&quot;</span><span class="br0">&#41;</span><span class="br0">&#93;</span></pre></td></tr></table></div></td></tr></tbody></table></div>А вот такое определение списка выдаст ошибку, потому что тип второго кортежа не такой как у первого:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="853685794"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="853685794" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#91;</span><span class="br0">&#40;</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="st0">&quot;three&quot;</span><span class="br0">&#41;</span>, <span class="br0">&#40;</span><span class="nu0">4</span>, <span class="st0">&quot;five&quot;</span><span class="br0">&#41;</span><span class="br0">&#93;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Результат:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="130910564"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="130910564" style="height: 286px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="de1"><pre class="de1"><span class="co1">-- TYPE MISMATCH --------------------------------------------- repl-temp-000.elm</span>
&nbsp;
The 1st <span class="kw3">and</span> 2nd elements are different types <span class="kw1">of</span> values.
&nbsp;
<span class="nu0">3</span>│ &nbsp; <span class="br0">&#91;</span><span class="br0">&#40;</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="st0">&quot;three&quot;</span><span class="br0">&#41;</span>, <span class="br0">&#40;</span><span class="nu0">4</span>, <span class="st0">&quot;five&quot;</span><span class="br0">&#41;</span><span class="br0">&#93;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">^^^^^^^^^^^</span>
The 1st element has this <span class="kw1">type</span><span class="sy0">:</span>
&nbsp;
&nbsp; &nbsp; <span class="br0">&#40;</span> number, number', <span class="kw4">String</span> <span class="br0">&#41;</span>
&nbsp;
But the 2nd is<span class="sy0">:</span>
&nbsp;
&nbsp; &nbsp; <span class="br0">&#40;</span> number, <span class="kw4">String</span> <span class="br0">&#41;</span>
&nbsp;
Hint<span class="sy0">:</span> All elements should be the same <span class="kw1">type</span> <span class="kw1">of</span> value so that we can <span class="kw3">iterate</span>
through the list without running into unexpected values.</pre></td></tr></table></div></td></tr></tbody></table></div>Когда списки слишком длинные, удобней разнести их объявление на несколько строк. Сделать это можно так:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="772864931"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="772864931" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1">aList <span class="sy0">=</span> <span class="br0">&#91;</span><span class="br0">&#40;</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="st0">&quot;three&quot;</span><span class="br0">&#41;</span>,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span><span class="nu0">4</span>, <span class="nu0">5</span>, <span class="st0">&quot;six&quot;</span><span class="br0">&#41;</span>,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span><span class="nu0">7</span>, <span class="nu0">8</span>, <span class="st0">&quot;nine&quot;</span><span class="br0">&#41;</span><span class="br0">&#93;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Но обычно (включая код ядра Elm), стиль кода для объявление списков в несколько строк, выглядит так:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="647767009"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="647767009" style="height: 110px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
</pre></td><td class="de1"><pre class="de1">aList <span class="sy0">:</span> List <span class="br0">&#40;</span>number, number, <span class="kw4">String</span><span class="br0">&#41;</span>
aList <span class="sy0">=</span> <span class="br0">&#91;</span> <span class="br0">&#40;</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="st0">&quot;three&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; , <span class="br0">&#40;</span><span class="nu0">4</span>, <span class="nu0">5</span>, <span class="st0">&quot;six&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; , <span class="br0">&#40;</span><span class="nu0">7</span>, <span class="nu0">8</span>, <span class="st0">&quot;nine&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#93;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Конечно, это дело вкуса, но, возможно, соблюдая такой стиль, другим людям будет проще разбираться в вашем коде.<br />
<br />
(Чтобы в elm-repl писать в несколько строк, просто в конце каждой строки пишите два символа \ чтобы было так: \\).<br />
<br />
Еще один способ создания списков - точечная нотация. Этот код создает список из элементов типа Int от 1 до 10:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="518809987"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="518809987" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#91;</span><span class="nu0">1</span>..<span class="nu0">10</span><span class="br0">&#93;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Результат:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="668547929"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="668547929" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#91;</span><span class="nu0">1</span>,<span class="nu0">2</span>,<span class="nu0">3</span>,<span class="nu0">4</span>,<span class="nu0">5</span>,<span class="nu0">6</span>,<span class="nu0">7</span>,<span class="nu0">8</span>,<span class="nu0">9</span>,<span class="nu0">10</span><span class="br0">&#93;</span> <span class="sy0">:</span> List number</pre></td></tr></table></div></td></tr></tbody></table></div>Последнее, но не менее важное. Помимо синтаксических структур, есть и другие способы создания списков. Например, вы можете использовать функцию модуля <font color="red">List.repeat</font>, которая принимает на вход целое число <font color="red">n</font> и произвольное значение, возвращает список с <font color="red">n</font> количеством копий переданного значения:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="520863244"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="520863244" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1"><span class="sy0">&gt;</span> List.<span class="kw3">repeat</span> <span class="nu0">4</span> <span class="st0">&quot;Elm&quot;</span>
<span class="br0">&#91;</span><span class="st0">&quot;Elm&quot;</span>,<span class="st0">&quot;Elm&quot;</span>,<span class="st0">&quot;Elm&quot;</span>,<span class="st0">&quot;Elm&quot;</span><span class="br0">&#93;</span> <span class="sy0">:</span> List <span class="kw4">String</span></pre></td></tr></table></div></td></tr></tbody></table></div><br />
<font size="3">Изменение списков</font><br />
<br />
Не смотря на то что раздел называется &quot;Изменение списков&quot;, вы не сможете изменить существующий список. В Elm все данные - не изменяемые. Все функции работы со списками создают новый список, оставляя исходный без изменений.<br />
<br />
Оператор <font color="red">::</font> добавляет элемент в начало списка:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="404231770"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="404231770" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1"><span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="sy0">::</span> <span class="br0">&#91;</span><span class="nu0">2</span>,<span class="nu0">3</span>,<span class="nu0">4</span><span class="br0">&#93;</span>
<span class="br0">&#91;</span><span class="nu0">1</span>,<span class="nu0">2</span>,<span class="nu0">3</span>,<span class="nu0">4</span><span class="br0">&#93;</span> <span class="sy0">:</span> List number</pre></td></tr></table></div></td></tr></tbody></table></div>Данный оператор можно применять сколько угодно раз. Вообще, вы всегда можете начинать с пустого списка и создавать его элемент за элементом:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="771348045"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="771348045" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1"><span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="sy0">::</span> <span class="nu0">2</span> <span class="sy0">::</span> <span class="nu0">3</span> <span class="sy0">::</span> <span class="nu0">4</span> <span class="sy0">::</span> <span class="br0">&#91;</span><span class="br0">&#93;</span>
<span class="br0">&#91;</span><span class="nu0">1</span>,<span class="nu0">2</span>,<span class="nu0">3</span>,<span class="nu0">4</span><span class="br0">&#93;</span> <span class="sy0">:</span> List number</pre></td></tr></table></div></td></tr></tbody></table></div>В Elm нет оператора, который добавляет элемент в конец списка. В любом случае, можно добавить в конец списка другой список:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="300360054"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="300360054" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1"><span class="sy0">&gt;</span> List.append <span class="br0">&#91;</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="nu0">3</span><span class="br0">&#93;</span> <span class="br0">&#91;</span><span class="nu0">4</span>, <span class="nu0">5</span><span class="br0">&#93;</span>
<span class="br0">&#91;</span><span class="nu0">1</span>,<span class="nu0">2</span>,<span class="nu0">3</span>,<span class="nu0">4</span>,<span class="nu0">5</span><span class="br0">&#93;</span> <span class="sy0">:</span> List number</pre></td></tr></table></div></td></tr></tbody></table></div>Так же есть оператор <font color="red">++</font>, который делает то же самое что и <font color="red">List.append</font>:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="439579128"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="439579128" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1"><span class="sy0">&gt;</span> <span class="br0">&#91;</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="nu0">3</span><span class="br0">&#93;</span> <span class="sy0">++</span> <span class="br0">&#91;</span><span class="nu0">4</span>, <span class="nu0">5</span><span class="br0">&#93;</span>
<span class="br0">&#91;</span><span class="nu0">1</span>,<span class="nu0">2</span>,<span class="nu0">3</span>,<span class="nu0">4</span>,<span class="nu0">5</span><span class="br0">&#93;</span> <span class="sy0">:</span> List number</pre></td></tr></table></div></td></tr></tbody></table></div>Добавление одиночного элемента в конец списка:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="614242991"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="614242991" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1"><span class="sy0">&gt;</span> <span class="br0">&#91;</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="nu0">3</span><span class="br0">&#93;</span> <span class="sy0">++</span> <span class="br0">&#91;</span><span class="nu0">4</span><span class="br0">&#93;</span>
<span class="br0">&#91;</span><span class="nu0">1</span>,<span class="nu0">2</span>,<span class="nu0">3</span>,<span class="nu0">4</span><span class="br0">&#93;</span> <span class="sy0">:</span> List number</pre></td></tr></table></div></td></tr></tbody></table></div>Другой способ создания одного списка из нескольких маленьких - функция <font color="red">concat</font>. Она принимает на вход список списков и объединяет их в один большой список:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="287789507"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="287789507" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1"><span class="sy0">&gt;</span> List.<span class="kw3">concat</span> <span class="br0">&#91;</span> <span class="br0">&#91;</span><span class="st0">&quot;one&quot;</span>, <span class="st0">&quot;two&quot;</span>, <span class="st0">&quot;three&quot;</span><span class="br0">&#93;</span>, <span class="br0">&#91;</span><span class="st0">&quot;four&quot;</span>, <span class="st0">&quot;five&quot;</span><span class="br0">&#93;</span>, <span class="br0">&#91;</span><span class="st0">&quot;six&quot;</span><span class="br0">&#93;</span>, <span class="br0">&#91;</span><span class="st0">&quot;seven&quot;</span>, <span class="st0">&quot;eight&quot;</span>, <span class="st0">&quot;nine&quot;</span><span class="br0">&#93;</span> <span class="br0">&#93;</span>
<span class="br0">&#91;</span><span class="st0">&quot;one&quot;</span>,<span class="st0">&quot;two&quot;</span>,<span class="st0">&quot;three&quot;</span>,<span class="st0">&quot;four&quot;</span>,<span class="st0">&quot;five&quot;</span>,<span class="st0">&quot;six&quot;</span>,<span class="st0">&quot;seven&quot;</span>,<span class="st0">&quot;eight&quot;</span>,<span class="st0">&quot;nine&quot;</span><span class="br0">&#93;</span> <span class="sy0">:</span> List <span class="kw4">String</span></pre></td></tr></table></div></td></tr></tbody></table></div><font size="3">Классика функционального программирования</font><br />
<br />
Теперь мы знаем несколько способов создания списков и работы с ними. Давайте рассмотрим несколько классических способов работы со спискам.<br />
<br />
Какое же функциональное программирование без функции map? Конечно же, в модуле <font color="red">List</font> есть такая! <font color="red">List.map</font> принимает функцию и список, затем применяет эту функцию ко всем элементам списка. В результате мы получим новый список, каждый элемент которого - результат применения функции к элементу исходного списка. Вот пример(введите <font color="red">import String</font> в REPL, чтобы пример был рабочий):<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="112913667"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="112913667" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1"><span class="sy0">&gt;</span> List.<span class="kw3">map</span> <span class="br0">&#40;</span><span class="sy0">\</span> word <span class="sy0">-&gt;</span> <span class="kw4">String</span>.<span class="kw3">length</span> word<span class="br0">&#41;</span> <span class="br0">&#91;</span><span class="st0">&quot;a&quot;</span>, <span class="st0">&quot;ab&quot;</span>, <span class="st0">&quot;abc&quot;</span><span class="br0">&#93;</span>
<span class="br0">&#91;</span><span class="nu0">1</span>,<span class="nu0">2</span>,<span class="nu0">3</span><span class="br0">&#93;</span> <span class="sy0">:</span> List <span class="kw4">Int</span></pre></td></tr></table></div></td></tr></tbody></table></div>В данном случае, мы применили функцию вычисляющую длину строки к каждой строке в списке.<br />
<br />
<font color="red">List.filter</font> - еще одна великолепная функция. Принимает на вход функцию и список, и удаляет из списка все элементы, для которых функция вернет <font color="red">false</font>. Пример ниже удаляет все отрицательные числа из списка:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="546577343"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="546577343" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1"><span class="sy0">&gt;</span> List.<span class="kw3">filter</span> <span class="br0">&#40;</span><span class="sy0">\</span> n <span class="sy0">-&gt;</span> <span class="br0">&#40;</span>n <span class="sy0">&gt;</span> <span class="nu0">0</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#91;</span><span class="sy0">-</span><span class="nu0">1</span>, <span class="nu0">3</span>, <span class="sy0">-</span><span class="nu0">2</span>, <span class="nu0">7</span><span class="br0">&#93;</span>
<span class="br0">&#91;</span><span class="nu0">3</span>,<span class="nu0">7</span><span class="br0">&#93;</span> <span class="sy0">:</span> List number</pre></td></tr></table></div></td></tr></tbody></table></div>В модуле <a rel="nofollow noopener noreferrer" href="http://package.elm-lang.org/packages/elm-lang/core/1.0.0/List" target="_blank" title="http://package.elm-lang.org/packages/elm-lang/core/1.0.0/List">List</a> очень многа полезных функций. Вот лишь некоторые из них:<br />
* <font color="red">List.head</font> возвращает перый элемент списка<br />
* <font color="red">List.tail</font> возвращает новый список без первого элемента исходного списка<br />
* <font color="red">List.foldl</font> и <font color="red">List.foldr</font> приводят список к одному элементу. Делается это так: берется первый и второй элемент списка, к ним применяется переданная функция, к результату применяется следущий элемент списка и так далее.<br />
<br />
Если в стандартном модуле <font color="red">List</font> нет необходимых вам функции, можно проверить модуль <a rel="nofollow noopener noreferrer" href="http://package.elm-lang.org/packages/circuithub/elm-list-extra/3.7.0/List-Extra" target="_blank" title="http://package.elm-lang.org/packages/circuithub/elm-list-extra/3.7.0/List-Extra">List.Extra</a>, содержаший функции с более расширенным функционалом.<br />
<br />
<a rel="nofollow noopener noreferrer" href="https://blog.codecentric.de/en/2015/12/elm-friday-part-07-lists/" target="_blank" title="https://blog.codecentric.de/en/2015/12/elm-friday-part-07-lists/">оригинал</a></div>

]]></content:encoded>
			<dc:creator>loothood</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/606805/4105.html</guid>
		</item>
		<item>
			<title>Пятничный Elm (Часть VI)</title>
			<link>https://www.cyberforum.ru/blogs/606805/4100.html</link>
			<pubDate>Wed, 27 Jan 2016 14:41:20 GMT</pubDate>
			<description>Пятничный Elm. Аннотации Типов (Часть VI) 
 
Одна из основных характеристик Elm - система...</description>
			<content:encoded><![CDATA[<div><font size="4">Пятничный Elm. Аннотации Типов (Часть VI)</font><br />
<br />
Одна из основных характеристик Elm - система статической типизации. Благодаря статической типизации, никогда не произойдет ошибок вида &quot;runtime exception&quot;, если программа прошла стадию компиляции. В данной заметке мы рассмотрим систему типов и аннотацию типов более подробно.<br />
<br />
<br />
<font size="3">О серии &quot;Пятничный Elm&quot;</font><br />
<br />
Это шестой пост серии заметок о языке программирования Elm.<br />
Цель данной серии - дать читателям знания от уровня &quot;Что такое Elm&quot; до &quot;Гуру Elm&quot;, шаг за шагом.<br />
<br />
<br />
<font size="3">Описания типов против интерфейса типов</font><br />
<br />
Не смотря на то что Elm - статически типизированный язык, в предыдущих статьях мы не описывали типы данных. Причина в том, что Elm может определить тип практически любого выражения самостоятельно. Давайте вспомним некоторые функции из <a href="https://www.cyberforum.ru/blogs/606805/blog4079.html">предыдущей</a> статьи и перепишем их с описанием типов. Тип функции объявляется в строке выше самой функции:<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="710477281"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="710477281" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
</pre></td><td class="de1"><pre class="de1"><span class="kw1">import</span> Html
&nbsp;
multiply <span class="sy0">:</span> number <span class="sy0">-&gt;</span> number <span class="sy0">-&gt;</span> number
multiply a b <span class="sy0">=</span> a <span class="sy0">*</span> b
&nbsp;
square <span class="sy0">:</span> number <span class="sy0">-&gt;</span> number
square a <span class="sy0">=</span> multiply a a
&nbsp;
productOfSquares <span class="sy0">:</span> number <span class="sy0">-&gt;</span> number <span class="sy0">-&gt;</span> number
productOfSquares a b <span class="sy0">=</span> multiply <span class="br0">&#40;</span>square a<span class="br0">&#41;</span> <span class="br0">&#40;</span>square b<span class="br0">&#41;</span>
&nbsp;
incrementAll <span class="sy0">:</span> List number <span class="sy0">-&gt;</span> List number
incrementAll list <span class="sy0">=</span> List.<span class="kw3">map</span> <span class="br0">&#40;</span><span class="sy0">\</span> n <span class="sy0">-&gt;</span> n <span class="sy0">+</span> <span class="nu0">1</span><span class="br0">&#41;</span> list
&nbsp;
incrementAll2 <span class="sy0">:</span> List number <span class="sy0">-&gt;</span> List number
incrementAll2 <span class="sy0">=</span> List.<span class="kw3">map</span> <span class="br0">&#40;</span><span class="sy0">\</span> n <span class="sy0">-&gt;</span> n <span class="sy0">+</span> <span class="nu0">1</span><span class="br0">&#41;</span>
&nbsp;
main <span class="sy0">:</span> Html.Html
main <span class="sy0">=</span>
&nbsp; <span class="kw1">let</span>
&nbsp; &nbsp; <span class="kw3">print</span> n <span class="sy0">=</span> Html.text <span class="sy0">&lt;|</span> toString n
&nbsp; <span class="kw1">in</span>
&nbsp; &nbsp; Html.p <span class="br0">&#91;</span><span class="br0">&#93;</span>
&nbsp; &nbsp; <span class="br0">&#91;</span> <span class="kw3">print</span> <span class="sy0">&lt;|</span> multiply <span class="nu0">3</span> <span class="nu0">5</span>
&nbsp; &nbsp; , Html.br <span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="br0">&#91;</span><span class="br0">&#93;</span>
&nbsp; &nbsp; , <span class="kw3">print</span> <span class="sy0">&lt;|</span> square <span class="nu0">4</span>
&nbsp; &nbsp; , Html.br <span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="br0">&#91;</span><span class="br0">&#93;</span>
&nbsp; &nbsp; , <span class="kw3">print</span> <span class="sy0">&lt;|</span> productOfSquares <span class="nu0">2</span> <span class="nu0">3</span>
&nbsp; &nbsp; , Html.br <span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="br0">&#91;</span><span class="br0">&#93;</span>
&nbsp; &nbsp; , <span class="kw3">print</span> <span class="sy0">&lt;|</span> incrementAll <span class="br0">&#91;</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="nu0">3</span><span class="br0">&#93;</span>
&nbsp; &nbsp; , Html.br <span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="br0">&#91;</span><span class="br0">&#93;</span>
&nbsp; &nbsp; , <span class="kw3">print</span> <span class="sy0">&lt;|</span> incrementAll2 <span class="br0">&#91;</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="nu0">3</span><span class="br0">&#93;</span>
&nbsp; &nbsp; <span class="br0">&#93;</span></pre></td></tr></table></div></td></tr></tbody></table></div><i>Я немного переписал функцию main - убрал дублирование преобразования из числа/списка в HTML text</i><br />
<br />
Для примера рассмотрим участок кода <font color="Red">square : number -&gt; number</font> - это аннотация для определения функции <font color="red">square</font>. Аннотация типов должна располагаться на строку выше, чем определение функции. Она состоит из имени функции, двоеточия и типов всех входных и выходных параметров, разделенных между собой стрелкой <font color="red">-&gt;</font>.<br />
<br />
Обратите внимание что в аннотации нет различий между входными и выходными параметрами. Например, для функции <font color="red">multiply</font>, в аннотации описаны три переменных типа number. Если вы изучали другие языки программирования, то, возможно, думали что аннотация для этой функции должна выглядеть так: <font color="red">(number, number) -&gt; number</font>, но это не так. Разделитель первых двух входных параметров <font color="red">-&gt;</font> точно такой же как и между вторым входным  и выходным параметрами. Объясняется это каррированием. Другими словами, функция <font color="red">multiply</font> принимает на вход только один параметр и возвращает функцию с аннотацией <font color="red">number -&gt; number</font>. Для иллюстрации:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="629424844"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="629424844" style="height: 190px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="de1"><pre class="de1"><span class="kw1">import</span> Html
&nbsp;
multiply <span class="sy0">:</span> number <span class="sy0">-&gt;</span> number <span class="sy0">-&gt;</span> number
multiply a b <span class="sy0">=</span> a <span class="sy0">*</span> b
&nbsp;
multiplyByFive <span class="sy0">:</span> number <span class="sy0">-&gt;</span> number
multiplyByFive <span class="sy0">=</span> multiply <span class="nu0">5</span>
&nbsp;
main <span class="sy0">:</span> Html.Html
main <span class="sy0">=</span> multiplyByFive <span class="nu0">3</span> <span class="sy0">|&gt;</span> toString <span class="sy0">|&gt;</span> Html.text</pre></td></tr></table></div></td></tr></tbody></table></div><br />
<font size="3">Композиция типов </font><br />
<br />
Давайте рассмотрим остальные функции из <a href="https://www.cyberforum.ru/blogs/606805/blog4079.html">предыдущей</a> статьи(и их аннотации типов):<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="774731521"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="774731521" style="height: 110px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
</pre></td><td class="de1"><pre class="de1">incrementAll <span class="sy0">:</span> List number <span class="sy0">-&gt;</span> List number
incrementAll list <span class="sy0">=</span> List.<span class="kw3">map</span> <span class="br0">&#40;</span><span class="sy0">\</span> n <span class="sy0">-&gt;</span> n <span class="sy0">+</span> <span class="nu0">1</span><span class="br0">&#41;</span> list
&nbsp;
incrementAll2 <span class="sy0">:</span> List number <span class="sy0">-&gt;</span> List number
incrementAll2 <span class="sy0">=</span> List.<span class="kw3">map</span> <span class="br0">&#40;</span><span class="sy0">\</span> n <span class="sy0">-&gt;</span> n <span class="sy0">+</span> <span class="nu0">1</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Эти функции работают со списками. Когда идет речь о списках, очень важным является тип элементов списка. Потому мы объявили что тип параметров не просто <font color="red">List</font>, а <font color="red">List number</font>, так как список состоит из элементов типа <font color="red">number</font>. Данный пример - пример основной концепции работы с типами данных, использующейся в Elm. Наиболее часто данная концепция встречается в контейнерах(таких как <a rel="nofollow noopener noreferrer" href="http://package.elm-lang.org/packages/elm-lang/core/2.1.0/List" target="_blank" title="http://package.elm-lang.org/packages/elm-lang/core/2.1.0/List">List</a> или <a rel="nofollow noopener noreferrer" href="http://package.elm-lang.org/packages/elm-lang/core/2.1.0/Maybe" target="_blank" title="http://package.elm-lang.org/packages/elm-lang/core/2.1.0/Maybe">Maybe</a>), и обычно, определяет какого типа элементы могут содержаться в этих структурах данных.<br />
<br />
<br />
<font size="3">Генерация аннотации типов автоматически</font><br />
<br />
Можно переложить на плечи компилятора задачу по определению типов функций и переменных. Для этого, надо скомпилировать код без аннотации типов с флагом <font color="red">--warn</font>.<br />
Например, если скомпилировать код из <a href="https://www.cyberforum.ru/blogs/606805/blog4079.html">предыдущей</a> заметки: <br />
<font color="red">elm-make --warn Fuctions.elm</font><br />
<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="613876321"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="613876321" style="height: 206px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="de1"><pre class="de1">=================================== WARNINGS ===================================
&nbsp;
<span class="re5">--</span> missing <span class="kw3">type</span> annotation <span class="re5">--------------------------------------</span> Functions.elm
&nbsp;
Top-level value <span class="sy0">`</span>multiply<span class="sy0">`</span> does not have a <span class="kw3">type</span> annotation.
&nbsp;
<span class="nu0">3</span>│ multiply a b = a <span class="sy0">*</span> b
&nbsp; &nbsp;^^^^^^^^^^^^^^^^^^^^
I inferred the <span class="kw3">type</span> annotation so you can copy it into your code:
&nbsp;
multiply : number -<span class="sy0">&gt;</span> number -<span class="sy0">&gt;</span> number</pre></td></tr></table></div></td></tr></tbody></table></div>Прекрасно не так ли?<br />
<br />
<br />
<font size="3">Подведем итоги</font><br />
<br />
Использовать аннотацию типов или нет - решать вам. В любом случае, в <a rel="nofollow noopener noreferrer" href="http://elm-lang.org/docs/style-guide" target="_blank" title="http://elm-lang.org/docs/style-guide">руководстве</a> Elm по стилистике кода дают совет использовать аннтоации для всех функций верхнего уровня. По моему опыту, гораздо проще находить ошибки в коде. И, честно говоря, даже компилятор может ошибиться в определении типа функции. Считаю что трата времени на ручную аннотацию, полностью окупается. <br />
<br />
Система типов в Elm гораздо больше, чем описана в статье - объединенные типы, алиасы типов, переменные типов, кортежи, записи и т.д. - все это будет рассмотрено в следующих статьях.<br />
<br />
<a rel="nofollow noopener noreferrer" href="https://blog.codecentric.de/en/2015/11/elm-friday-part-06-type-annotations/" target="_blank" title="https://blog.codecentric.de/en/2015/11/elm-friday-part-06-type-annotations/">оригинал</a></div>

]]></content:encoded>
			<dc:creator>loothood</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/606805/4100.html</guid>
		</item>
		<item>
			<title>Пятничный Elm (Часть V)</title>
			<link>https://www.cyberforum.ru/blogs/606805/4079.html</link>
			<pubDate>Fri, 15 Jan 2016 10:55:33 GMT</pubDate>
			<description>Пятничный Elm. Функции (Часть V) 
 
Мы уже рассматривали функции в предыдущих статьях. Эта статья...</description>
			<content:encoded><![CDATA[<div><font size="4">Пятничный Elm. Функции (Часть V)</font><br />
<br />
Мы уже рассматривали функции в предыдущих статьях. Эта статья посвящена объявлению и вызовам функций.<br />
<br />
<br />
<font size="3">О серии &quot;Пятничный Elm&quot;</font><br />
<br />
Это пятый пост серии заметок о языке программирования Elm.<br />
Цель данной серии - дать читателям знания от уровня &quot;Что такое Elm&quot; до &quot;Гуру Elm&quot;, шаг за шагом.<br />
<br />
<br />
<font size="3">Функции</font> <br />
<br />
Так выглядит определение функции в Elm:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="874345912"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="874345912" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">multiply a b <span class="sy0">=</span> a <span class="sy0">*</span> b</pre></td></tr></table></div></td></tr></tbody></table></div>Определение начинается с имени функции, за которым следует список входных параметров. В отличие от С-подобных языков, таких как Java, JavaScript и т.д., здесь нет скобок, запятых и прочих разделителей между параметрами - только пробелы.<br />
<br />
Знак сравнения <font color="Red">=</font> отделяет имя функции со списком параметров от тела функции. Тело функции - это любой код на Elm, который возвращает значение. В теле функции могут быть использованы параметры, которые перечислены после имени функции.<br />
<br />
Функции, которые мы объявили, могут быть вызваны другими функциями, например:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="971196891"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="971196891" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">square a <span class="sy0">=</span> multiply a a</pre></td></tr></table></div></td></tr></tbody></table></div>Мы определили функцию <font color="red">square</font> которая использует функцию <font color="red">multiply</font>, объявленную ранее. При вызове функции, так же и при ее определении, не нужны скобки, запятые. Просто имя функции и переданные в нее параметры, разделенные пробелами.<br />
<br />
Но, когда в качестве параметров, мы передаем выражения, то скобки обязательны:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="876254616"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="876254616" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">productOfSquares a b <span class="sy0">=</span> multiply <span class="br0">&#40;</span>square a<span class="br0">&#41;</span> <span class="br0">&#40;</span>square b<span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Так же можно объявлять анонимные функции(известны как лямбда) &quot;на лету&quot;:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="444087623"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="444087623" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">incrementAll list <span class="sy0">=</span> List.<span class="kw3">map</span> <span class="br0">&#40;</span><span class="sy0">\</span> n <span class="sy0">-&gt;</span> n <span class="sy0">+</span> <span class="nu0">1</span><span class="br0">&#41;</span> list</pre></td></tr></table></div></td></tr></tbody></table></div>Анонимные функции находятся внутри <font color="red">(\</font> и <font color="red">)</font>. В данном случае, функция принимает один параметр и прибавляет к его значению единицу. Благодаря использованию <font color="red">List.map</font>, эта функция будет применена ко всем элементам списка <font color="red">list</font>.<br />
<br />
На самом деле, можно записать короче. Эта функция эквивалентна той что выше:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="953102556"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="953102556" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">incrementAll2 <span class="sy0">=</span> List.<span class="kw3">map</span> <span class="br0">&#40;</span><span class="sy0">\</span> c <span class="sy0">-&gt;</span> c <span class="sy0">+</span> <span class="nu0">1</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Это возможно благодаря тому, что Elm поддерживает нечто, что называется *каррирование*. Функция <font color="red">incrementAll</font> принимает как входной параметр список и возвращает другой список. Функция <font color="red">incrementAll2</font> не принимает никаких аргументов и вовзращает другую функцию.<br />
<br />
Так, когда мы пишем <font color="red">incrementAll2 [1, 2, 3]</font>, Elm вычисляет значение <font color="red">incrementAll2</font>, в результате получает функцию, которую применяет к оставшимся параметрам(в нашем случае - к параметру [1,2,3]). Результат тот же самый.<br />
<br />
Ничего страшного, если каррирование показалось вам слишком сложным. Понимание обязательно придет, а пока что не стоит волноваться об этом. А пока что вы можете писать функции без не используя каррирование. <br />
<br />
Давайте объединим все функции, которые объявили выше в одну программу:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="310629601"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="310629601" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="de1"><pre class="de1"><span class="kw1">import</span> Html
&nbsp;
multiply a b <span class="sy0">=</span> a <span class="sy0">*</span> b
&nbsp;
square a <span class="sy0">=</span> multiply a a
&nbsp;
productOfSquares a b <span class="sy0">=</span> multiply <span class="br0">&#40;</span>square a<span class="br0">&#41;</span> <span class="br0">&#40;</span>square b<span class="br0">&#41;</span>
&nbsp;
incrementAll list <span class="sy0">=</span> List.<span class="kw3">map</span> <span class="br0">&#40;</span><span class="sy0">\</span> c <span class="sy0">-&gt;</span> c <span class="sy0">+</span> <span class="nu0">1</span><span class="br0">&#41;</span> list
&nbsp;
incrementAll2 <span class="sy0">=</span> List.<span class="kw3">map</span> <span class="br0">&#40;</span><span class="sy0">\</span> c <span class="sy0">-&gt;</span> c <span class="sy0">+</span> <span class="nu0">1</span><span class="br0">&#41;</span>
&nbsp;
main <span class="sy0">=</span> Html.p <span class="br0">&#91;</span><span class="br0">&#93;</span>
&nbsp; <span class="br0">&#91;</span> Html.text <span class="br0">&#40;</span><span class="st0">&quot;3 × 5 &nbsp; = &quot;</span> <span class="sy0">++</span> <span class="br0">&#40;</span>toString <span class="br0">&#40;</span>multiply <span class="nu0">3</span> <span class="nu0">5</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; , Html.br <span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="br0">&#91;</span><span class="br0">&#93;</span>
&nbsp; , Html.text <span class="br0">&#40;</span><span class="st0">&quot;4² &nbsp; &nbsp; &nbsp;= &quot;</span> <span class="sy0">++</span> <span class="br0">&#40;</span>toString <span class="br0">&#40;</span>square <span class="nu0">4</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; , Html.br <span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="br0">&#91;</span><span class="br0">&#93;</span>
&nbsp; , Html.text <span class="br0">&#40;</span><span class="st0">&quot;2² × 3² = &quot;</span> <span class="sy0">++</span> <span class="br0">&#40;</span>toString <span class="br0">&#40;</span>productOfSquares <span class="nu0">2</span> <span class="nu0">3</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; , Html.br <span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="br0">&#91;</span><span class="br0">&#93;</span>
&nbsp; , Html.text <span class="br0">&#40;</span><span class="st0">&quot;incrementAll [1, 2, 3] = &quot;</span> <span class="sy0">++</span> <span class="br0">&#40;</span>toString <span class="br0">&#40;</span>incrementAll <span class="br0">&#91;</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="nu0">3</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; , Html.br <span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="br0">&#91;</span><span class="br0">&#93;</span>
&nbsp; , Html.text <span class="br0">&#40;</span><span class="st0">&quot;incrementAll2 [1, 2, 3] = &quot;</span> <span class="sy0">++</span> <span class="br0">&#40;</span>toString <span class="br0">&#40;</span>incrementAll2 <span class="br0">&#91;</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="nu0">3</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; <span class="br0">&#93;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Рассмотрим подробнее функцию <font color="red">main</font>. Функция возвращает числа и списки(в случае incrementAll и incrementAll2). Эти данные нам необходимо преобразовать в тип String с помощью функции toString(которая объявлена в библиотеке <font color="red">Basics</font>, которая импортируется по умолчанию). Чтобы склеить строки, мы используем оператор <font color="red">++</font>. И, наконец, полученные строки приводим к типу HTML text с помощью функции <font color="red">Html.text</font>. <br />
<br />
<br />
<font size="3">Способы применения функций</font><br />
<br />
Давайте подробней рассмотрим участок кода <font color="red">Html.text (&quot;3 &#215; 5 = &quot; ++ (toString (multiply 3 5)))</font>. Многовато скобок. Вам так не кажется? В Elm есть два оператора <font color="red">|&gt;</font> и <font color="red">&lt;|</font> - с помощью них,можно переписать этот код более элегантно, но сперва давайте поймем что эти операторы делают:  <ul><li><font color="red">|&gt;</font>: Берет выражение левее оператора и передает это выражение как входной параметр функции, которая находится правее этого оператора.</li>
<li> <font color="red">&lt;|</font>: Берет выражение правее оператора и передает это выражение как входной параметр функции, которая находится левее этого оператора.</li>
</ul><br />
Вот функция main из предыдущего примера, переписанная с использованием этих операторов:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="660020579"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="660020579" style="height: 206px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="de1"><pre class="de1">main <span class="sy0">=</span> Html.p <span class="br0">&#91;</span><span class="br0">&#93;</span>
&nbsp; <span class="br0">&#91;</span> Html.text <span class="sy0">&lt;|</span> <span class="st0">&quot;3 × 5 &nbsp; = &quot;</span> <span class="sy0">++</span> <span class="br0">&#40;</span>toString <span class="sy0">&lt;|</span> multiply <span class="nu0">3</span> <span class="nu0">5</span><span class="br0">&#41;</span>
&nbsp; , Html.br <span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="br0">&#91;</span><span class="br0">&#93;</span>
&nbsp; , Html.text <span class="sy0">&lt;|</span> <span class="st0">&quot;4² &nbsp; &nbsp; &nbsp;= &quot;</span> <span class="sy0">++</span> <span class="br0">&#40;</span>toString <span class="sy0">&lt;|</span> square <span class="nu0">4</span><span class="br0">&#41;</span>
&nbsp; , Html.br <span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="br0">&#91;</span><span class="br0">&#93;</span>
&nbsp; , Html.text <span class="sy0">&lt;|</span> <span class="st0">&quot;2² × 3² = &quot;</span> <span class="sy0">++</span> <span class="br0">&#40;</span>toString <span class="sy0">&lt;|</span> productOfSquares <span class="nu0">2</span> <span class="nu0">3</span><span class="br0">&#41;</span>
&nbsp; , Html.br <span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="br0">&#91;</span><span class="br0">&#93;</span>
&nbsp; , Html.text <span class="sy0">&lt;|</span> <span class="st0">&quot;incrementAll [1, 2, 3] = &quot;</span> <span class="sy0">++</span> <span class="br0">&#40;</span>toString <span class="sy0">&lt;|</span> incrementAll <span class="br0">&#91;</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="nu0">3</span><span class="br0">&#93;</span><span class="br0">&#41;</span>
&nbsp; , Html.br <span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="br0">&#91;</span><span class="br0">&#93;</span>
&nbsp; , Html.text <span class="sy0">&lt;|</span> <span class="st0">&quot;incrementAll2 [1, 2, 3] = &quot;</span> <span class="sy0">++</span> <span class="br0">&#40;</span>toString <span class="sy0">&lt;|</span> incrementAll2 <span class="br0">&#91;</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="nu0">3</span><span class="br0">&#93;</span><span class="br0">&#41;</span>
&nbsp; <span class="br0">&#93;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Можно даже переписать <br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="570216662"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="570216662" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">Html.text <span class="sy0">&lt;|</span> <span class="st0">&quot;3 × 5 &nbsp; = &quot;</span> <span class="sy0">++</span> <span class="br0">&#40;</span>toString <span class="sy0">&lt;|</span> multiply <span class="nu0">3</span> <span class="nu0">5</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>вот так:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="274214158"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="274214158" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">Html.text <span class="sy0">&lt;|</span> <span class="br0">&#40;</span><span class="sy0">++</span><span class="br0">&#41;</span> <span class="st0">&quot;3 × 5 &nbsp; = &quot;</span> <span class="sy0">&lt;|</span> toString <span class="sy0">&lt;|</span> multiply <span class="nu0">3</span> <span class="nu0">5</span></pre></td></tr></table></div></td></tr></tbody></table></div>или даже так:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="545259140"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="545259140" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">square <span class="nu0">4</span> <span class="sy0">|&gt;</span> toString <span class="sy0">|&gt;</span> <span class="br0">&#40;</span><span class="sy0">++</span><span class="br0">&#41;</span> <span class="st0">&quot;4² &nbsp; &nbsp; &nbsp;= &quot;</span> <span class="sy0">|&gt;</span> Html.text</pre></td></tr></table></div></td></tr></tbody></table></div>Тут мы использовали инфиксный оператор <font color="red">++</font> как префиксный, чтобы у нас получилось применить его вместе с <font color="red">|&gt;</font> и <font color="red">&lt;|</font>. Так же, мы применили немного каррирования: <font color="red">(++) </font>принимает на вход две строки(объединяет их в одну). Выражение (++) <font color="red">&quot;3 &#215; 5 = &quot; </font>- частичное применение функции. Вторую часть мы получаем из оператора <font color="red">&lt;|</font>.<br />
Очень похоже команду на <font color="red">|</font> bash. Не правда ли?<br />
<br />
Чтобы с легкостью читать код в таком стиле, представьте что мы движемся по трубопроводу. Используя <font color="red">|&gt;</font>- слева направо, используя <font color="red">&lt;|</font> - справа налево. Например, строку <font color="red">Html.text &lt;| (++) &quot;3 &#215; 5 = &quot; &lt;| toString &lt;| multiply 3 5</font>начинаем читать с конца(<font color="red">multiply 3 5</font>), результат функции подается на вход <font color="red">toString</font>, чтобы преобразовать число в строку, результат передается вторым параметром в функцию аппликации (<font color="red">(++)</font>). Строка, получившаяся в итоге - входной параметр для <font color="red">Html.text</font>.<br />
<br />
<a rel="nofollow noopener noreferrer" href="https://blog.codecentric.de/en/2015/11/elm-friday-part-05-functions/" target="_blank" title="https://blog.codecentric.de/en/2015/11/elm-friday-part-05-functions/">оригинал</a></div>

]]></content:encoded>
			<dc:creator>loothood</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/606805/4079.html</guid>
		</item>
		<item>
			<title>Пятничный Elm (Часть IV)</title>
			<link>https://www.cyberforum.ru/blogs/606805/4071.html</link>
			<pubDate>Sat, 09 Jan 2016 12:43:22 GMT</pubDate>
			<description><![CDATA[Пятничный Elm. Hello World 2.0 (Часть IV) 
 
 
О серии "Пятничный Elm" 
 
Это четвертый пост серии...]]></description>
			<content:encoded><![CDATA[<div><font size="4">Пятничный Elm. Hello World 2.0 (Часть IV)</font><br />
<br />
<br />
<font size="3">О серии &quot;Пятничный Elm&quot;</font><br />
<br />
Это четвертый пост серии заметок о языке программирования Elm.<br />
Цель данной серии - дать читателям знания от уровня &quot;Что такое Elm&quot; до &quot;Гуру Elm&quot;, шаг за шагом.<br />
<br />
<br />
<font size="3">Hello World 2.0</font> <br />
<br />
&quot;Ноги растут&quot; из <a href="https://www.cyberforum.ru/blogs/606805/blog4070.html">предыдущей статьи</a> в которой мы написали первую программу на Elm. Напечатать небольшую строку - это, без сомнения, подвиг, но Elm может кое-что еще.   <br />
Вот пример как Elm работает со структурами данных и отображает их в HTML(эта программа сортирует список строк и выводит их):<br />
<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="662014763"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="662014763" style="height: 222px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="de1"><pre class="de1"><span class="kw1">import</span> Html
&nbsp;
names <span class="sy0">=</span> <span class="br0">&#91;</span> <span class="st0">&quot;Pearl&quot;</span>, <span class="st0">&quot;Steven&quot;</span>, <span class="st0">&quot;Garnet&quot;</span>, <span class="st0">&quot;Amethyst&quot;</span> <span class="br0">&#93;</span>
&nbsp;
main <span class="sy0">=</span>
&nbsp; <span class="kw1">let</span>
&nbsp; &nbsp; sorted <span class="sy0">=</span> List.sort names
&nbsp; &nbsp; texts <span class="sy0">=</span> List.<span class="kw3">map</span> Html.text sorted
&nbsp; &nbsp; textToItem text <span class="sy0">=</span> Html.li <span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="br0">&#91;</span> text <span class="br0">&#93;</span>
&nbsp; &nbsp; items <span class="sy0">=</span> List.<span class="kw3">map</span> textToItem texts
&nbsp; <span class="kw1">in</span>
&nbsp; &nbsp; Html.ul <span class="br0">&#91;</span><span class="br0">&#93;</span> items</pre></td></tr></table></div></td></tr></tbody></table></div>Сохраните код в файле и посмотрите результат работы программы в браузере.<br />
<br />
В примере используется несколько новых концепций Elm. Давайте рассмотрим их:<ul><li> <font color="Red">names</font> объявлена как список строк.</li>
<li> <font color="red">main</font> - входная точка нашей программы, так же как и в примере про Hello World, хотя и немного сложнее.</li>
<li> Тело функции <font color="red">main</font> разделено на две части:</li>
</ul><blockquote><ul><li> в части <font color="red">let</font> мы определили довольно много переменных</li>
<li>  которые использовали в части <font color="red">in</font></li>
</ul></blockquote><ul><li> <font color="red">sorted</font>: мы использовали <font color="red">List.sort</font> чтобы отсортировать имена в алфавитном порядке</li>
<li> <font color="red">texts</font>: мы использовали <font color="red">List.map</font> чтобы применить функцию <font color="red">Html.text</font> к каждому элементу отсортированного списка. Результат: список элементов типа <font color="red">HTML.text</font>. (Elm не отображает тип данных строка в браузере. Вы всегда должны привести строки к типу HTML.text чтобы отобразить данные).</li>
<li> <font color="red">textToItem</font> объявляет новую функцию &quot;на лету&quot;. Каждый элемент HTML.text оборачивается в функцию HTML.li, которая по сути является тегом</li>
<li> <font color="red">items</font>: мы снова использовали <font color="red">List.map</font> чтобы применить функцию <font color="red">textToItem</font> к каждому элементу списка <font color="red">texts</font>. В результате получаем список элементов HTML <font color="red">li</font>.</li>
<li> Наконец, в части программы <font color="red">in</font> функции <font color="red">main</font> мы оборачиваем в список элементов <font color="red">li</font> в элемент HTML <font color="red">ul</font> который переводит в тег <font color="red">&lt;ul&gt;</font></li>
</ul><br />
<br />
<font size="3">Атрибуты</font> <br />
<br />
Возможно, вы обратили внимание на пустой список [] вторым параметром, когда мы вызывали функции <font color="red">Html.li</font> и <font color="red">Html.ul</font>. Почти все функции из модуля <font color="red">HTML</font> принимают два аргумента: список атрибутов и список внутренних элементов. Первый аргумент(атрибуты) может быть использован чтобы установить css класс, внутренние стили, слушатель событий или что-нибудь еще, что можно представить как атрибут HTML. Второй аргумент - список внутренних элементов - список HTML элементов которые могут быть представлены как новый HTML элемент.   <br />
Давайте рассмотрим подробнее. Этот код устанавливает некоторые внутренние стили для отображения контента по центру страницы и меняет шрифт:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="831342762"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="831342762" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="de1"><pre class="de1"><span class="kw1">import</span> Html
<span class="kw1">import</span> Html.Attributes
&nbsp;
names <span class="sy0">=</span> <span class="br0">&#91;</span> <span class="st0">&quot;Pearl&quot;</span>, <span class="st0">&quot;Steven&quot;</span>, <span class="st0">&quot;Garnet&quot;</span>, <span class="st0">&quot;Amethyst&quot;</span> <span class="br0">&#93;</span>
&nbsp;
main <span class="sy0">=</span>
&nbsp; <span class="kw1">let</span>
&nbsp; &nbsp; sorted <span class="sy0">=</span> List.sort names
&nbsp; &nbsp; texts <span class="sy0">=</span> List.<span class="kw3">map</span> Html.text sorted
&nbsp; &nbsp; textToItem text <span class="sy0">=</span>
&nbsp; &nbsp; &nbsp; Html.li
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span> Html.Attributes.style <span class="br0">&#91;</span><span class="br0">&#40;</span><span class="st0">&quot;font-style&quot;</span>, <span class="st0">&quot;italic&quot;</span><span class="br0">&#41;</span> <span class="br0">&#93;</span> <span class="br0">&#93;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span> text <span class="br0">&#93;</span>
&nbsp; &nbsp; items <span class="sy0">=</span> List.<span class="kw3">map</span> textToItem texts
&nbsp; <span class="kw1">in</span>
&nbsp; &nbsp; Html.<span class="kw3">div</span>
&nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span> Html.Attributes.style
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span> <span class="br0">&#40;</span><span class="st0">&quot;position&quot;</span>, <span class="st0">&quot;absolute&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; , <span class="br0">&#40;</span><span class="st0">&quot;width&quot;</span>, <span class="st0">&quot;10em&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; , <span class="br0">&#40;</span><span class="st0">&quot;height&quot;</span>, <span class="st0">&quot;10em&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; , <span class="br0">&#40;</span><span class="st0">&quot;top&quot;</span>, <span class="st0">&quot;50%&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; , <span class="br0">&#40;</span><span class="st0">&quot;left&quot;</span>, <span class="st0">&quot;50%&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; , <span class="br0">&#40;</span><span class="st0">&quot;transform&quot;</span>, <span class="st0">&quot;translateX(-50%) translateY(-50%)&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; , <span class="br0">&#40;</span><span class="st0">&quot;overflow&quot;</span>, <span class="st0">&quot;hidden&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#93;</span>
&nbsp; &nbsp; &nbsp; <span class="br0">&#93;</span>
&nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span> Html.ul <span class="br0">&#91;</span><span class="br0">&#93;</span> items <span class="br0">&#93;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Мы импортировали новый модуль <font color="red">Html.Attributes</font>, в котором описаны функции для работы с атрибутами. В данном случае есть два отличия от предыдущего примера:<br />
У элементов <font color="red">li</font> теперь не пустой список атрибутов. Мы использовали функцию <font color="red">Html.Attributes.style</font> чтобы установить стиль <font color="red">font-style</font>.<br />
Так же мы обернули тег <font color="red">&lt;ul&gt;</font> в div, который так же содержит список внутренних стилей. Эти стили отображают div в центре страницы.<br />
<br />
В примере можно увидеть новые типы данных. Функция <font color="red">style</font> принимает список кортежей. Кортежи чем-то похожи на списки - они так же могут содержать коллекции из нескольких элементов. Но есть два важных отличия: все элементы списка должны быть одинакового типа и у списков нет фиксированной длины. Элементы кортежа могут быть различных типов, но длина кортежа фиксирована. Количество элементов и их типы вместе составляют тип кортежа. Таким образом, вы не можете передать кортеж с тремя(или одним) элементом в функции, которые ожидают кортежи из двух элементов. Другими словами, кортежи - это пары(или триплеты, четверки,...) значений. В Elm кортежи заключены в круглые скобки.<br />
<br />
В нашем случае, каждый стиль - это кортеж из двух строк и аргумент стиля - перечень таких кортежей.<br />
<br />
<a rel="nofollow noopener noreferrer" href="https://blog.codecentric.de/en/2015/11/elm-friday-part-04-hello-world-2-0/" target="_blank" title="https://blog.codecentric.de/en/2015/11/elm-friday-part-04-hello-world-2-0/">оригинал</a></div>

]]></content:encoded>
			<dc:creator>loothood</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/606805/4071.html</guid>
		</item>
		<item>
			<title>Пятничный Elm (Часть III)</title>
			<link>https://www.cyberforum.ru/blogs/606805/4070.html</link>
			<pubDate>Sat, 09 Jan 2016 10:55:50 GMT</pubDate>
			<description><![CDATA[*Пятничный Elm. Что такое Elm (Часть III)* 
 
 
О серии "Пятничный Elm" 
 
Это третий пост серии...]]></description>
			<content:encoded><![CDATA[<div><b><font size="4">Пятничный Elm. Что такое Elm (Часть III)</font></b><br />
<br />
<br />
<font size="3">О серии &quot;Пятничный Elm&quot;</font><br />
<br />
Это третий пост серии заметок о языке программирования Elm.<br />
Цель данной серии - дать читателям знания от уровня &quot;Что такое Elm&quot; до &quot;Гуру Elm&quot;, шаг за шагом.<br />
<br />
<br />
<font size="3">Приступим</font><br />
<br />
Создадим новую папку, например, elm-playground. Перейдем в нее. Прежде чем писать код, ма должны выполнить одну команду. Введите в консоли:<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="513696931"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="513696931" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1"><span class="co4">you@localhost:~$ </span>elm-package <span class="kw2">install</span> <span class="re5">--yes</span> evancz<span class="sy0">/</span>elm-html</pre></td></tr></table></div></td></tr></tbody></table></div>Так мы установим библиотеку HTML со всеми зависимостями. <font color="Red">elm-package install</font> работает аналогично <font color="Red">npm install</font>. Мы рассмотрим систему пакетов Elm в другом посте этой серии заметок.<br />
<br />
<br />
<font size="3">Elm Hello World</font><br />
<br />
Теперь напишем первую программу. По традиции, как было принято испокон веков(да-да! аж с 01.01.1970), программа будет выводить текст &quot;Hello World&quot;.<br />
Заходим в папку elm-playground, создаем файл HelloWorld.elm и пишем в нем:<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="923589760"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="923589760" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1"><span class="kw1">import</span> Html
&nbsp;
main <span class="sy0">=</span> Html.text <span class="st0">&quot;Hello, World!&quot;</span></pre></td></tr></table></div></td></tr></tbody></table></div><i>В Light Table нажимаем сочетание клавиш <font color="Red">Ctrl+Space</font> и набираем elm-reactor.<br />
В нашей IDE откроется имитатор бразуера, на странице будет написано &quot;Hello, World!&quot;<br />
</i><br />
Если решили не использовать Ligth Table, надо перейти в папку elm-playground, набрать команду elm-reactor, после чего открыть в любом браузере адрес <a rel="nofollow noopener noreferrer" href="http://0.0.0.0:8000/" target="_blank" title="http://0.0.0.0:8000/">http://0.0.0.0:8000/</a> .<br />
Будет отображено содержимое папки, в которой запушен elm-reactor, по нажатию на файл  HelloWorld.elm, увидем результат работы первой программы.<br />
<br />
<i>есть третий способ запуска программы - надо перейти по <a rel="nofollow noopener noreferrer" href="http://elm-lang.org/try" target="_blank" title="http://elm-lang.org/try">этой</a> ссылке, вставить код в левую часть окна и нажать Compile</i><br />
<br />
<br />
<font size="3">Что же это произошло?</font><br />
<br />
Давайте разберем программу. Начнем с последней строки. Точка входа в нашу программу - функция <font color="red">main</font>. У каждой программы на Elm должна быть эта функция. Говоря языком JavaScript, main возвращает некоторый <font color="red">HTML</font>. В нашем случае, main не имеет входных параметров и возвращает статичный элемент <font color="red">Html.text</font>, которому на вход подается строка.<br />
<br />
В свою очередь, <font color="red">Html.text</font> - функция модуля <font color="red">Html</font>, который мы импортнули в первой строке. Это модуль из пакета <font color="red">evancz/elm-html</font>, который мы ранее установили командой <font color="red">elm-package install</font>. Мы должны использовать префикс <font color="red">Html</font> всегда, когда хотим вызвать функции из этого модуля, например, <font color="red">Html.div</font>, <font color="red">Html.span</font> или, как в нашем случае, <font color="red">Html.text</font>. Есть способы обойти это ограничение, если вы предпочитаете краткость многословности в коде - я объясню как, когда более подробно будем рассмаотривать команду <font color="red">import</font>.<br />
<br />
<br />
<font size="3">&quot;Живая перезагрузка&quot;</font><br />
<br />
Теперь измените строку &quot;Hello, World!&quot; на, допустим, &quot;Elm rocks!&quot; и сохраните файл. Если вы перезагрузите страницу в браузере, elm-reactor автоматически скомпилирует новый результат программы.<br />
<br />
Это великолепно, не так ли? Но eml-reactor может больше! Откройте опять <a rel="nofollow noopener noreferrer" href="http://localhost:8000/" target="_blank" title="http://localhost:8000/">http://localhost:8000/</a>. На этот раз не надо жать на<br />
HelloWorld.elm. Нажмите на иконку гаечного ключа рядом с этим файлом. Таким образом вы открыли отладчик. Того же эффекта можно было добиться, если в адресной строке браузера, к адресу <a rel="nofollow noopener noreferrer" href="http://localhost:8000/HelloWorld.elm" target="_blank" title="http://localhost:8000/HelloWorld.elm">http://localhost:8000/HelloWorld.elm</a> дописать <font color="red">?debug</font> чтобы получилось так:<br />
<a rel="nofollow noopener noreferrer" href="http://localhost:8000/HelloWorld.elm?debug" target="_blank" title="http://localhost:8000/HelloWorld.elm?debug">http://localhost:8000/HelloWorld.elm?debug</a><br />
<br />
Давайте пока что не обращать внимание на панель отладчика.<br />
Измените текст &quot;Elm Rocks!&quot; еще раз и сохраните файл. Отладчик отловит изменения, перекомпилирует автоматически и перезагрузит страницу бразуера самостоятельно. Прекрасно, не так ли?<br />
<br />
Если &quot;живая&quot; перезагрузка страницы не работает, возможно вы установили elm v0.16.0 с помощью npm. Вы можете попробовать поставить другую верисию elm. Например, <font color="red">npm install -g elm@0.15.1-beta4</font>.<br />
<br />
<a rel="nofollow noopener noreferrer" href="https://blog.codecentric.de/en/2015/11/elm-friday-part-03-hello-world/" target="_blank" title="https://blog.codecentric.de/en/2015/11/elm-friday-part-03-hello-world/">оригинал</a> данной статьи</div>

]]></content:encoded>
			<dc:creator>loothood</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/606805/4070.html</guid>
		</item>
		<item>
			<title>Установка Elm</title>
			<link>https://www.cyberforum.ru/blogs/606805/4069.html</link>
			<pubDate>Sat, 09 Jan 2016 10:45:00 GMT</pubDate>
			<description>*Установка Elm и настройка IDE 
* 
 
Всем привет! 
Это должна быть вторая часть серии постов...</description>
			<content:encoded><![CDATA[<div><b><font size="4">Установка Elm и настройка IDE<br />
</font></b><br />
<br />
Всем привет!<br />
Это должна быть вторая часть серии постов &quot;Пятничный Elm&quot;, но описание в <a rel="nofollow noopener noreferrer" href="https://blog.codecentric.de/en/2015/11/elm-friday-part-02-installing-elm/" target="_blank" title="https://blog.codecentric.de/en/2015/11/elm-friday-part-02-installing-elm/">оригинале</a> не включает в себя сборку из исходников, потому я решил написать этот пост сам.<br />
<br />
<i>Весь инструментарий будет установлен на Ubuntu 15.04. Установка на IOS или Windows описана на официальных сайтах.</i><br />
<br />
<br />
<font size="3">Инструментарий:</font><ul><li>Язык программирования Haskell. <a rel="nofollow noopener noreferrer" href="https://www.haskell.org" target="_blank" title="https://www.haskell.org">Сайт</a></li>
<li>Программа git <a rel="nofollow noopener noreferrer" href="https://github.com" target="_blank" title="https://github.com">Сайт</a></li>
<li>Пакет nodejs <a rel="nofollow noopener noreferrer" href="https://nodejs.org/en" target="_blank" title="https://nodejs.org/en">Сайт</a></li>
<li>Программа curl <a rel="nofollow noopener noreferrer" href="http://curl.haxx.se" target="_blank" title="http://curl.haxx.se">Сайт</a></li>
<li>Язык программирования Elm. <a rel="nofollow noopener noreferrer" href="http://elm-lang.org" target="_blank" title="http://elm-lang.org">Сайт</a></li>
<li>IDE - Light Table. <a rel="nofollow noopener noreferrer" href="http://lighttable.com" target="_blank" title="http://lighttable.com">Сайт</a></li>
<li>Плагин для языка Elm к IDE. <a rel="nofollow noopener noreferrer" href="https://github.com/rundis/elm-light" target="_blank" title="https://github.com/rundis/elm-light">Сайт</a></li>
</ul><br />
<i><br />
Чтобы установить первым способом, будет достаточно только nodeJS и npm</i><br />
<br />
<br />
<font size="3">Установка Haskell</font><br />
<br />
Так как компилятор Elm написан на Haskell, сначала надо установить язык программирования Haskell<br />
Установка довольно проста и проиcходит без проблем. Все что надо сделать, выполнить следующие команды:<br />
<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="638906719"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="638906719" style="height: 174px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
</pre></td><td class="de1"><pre class="de1"><span class="co4">you@locatlhost:~$ </span><span class="kw2">sudo</span> <span class="kw2">apt-get update</span>
<span class="co4">you@locatlhost:~$ </span><span class="kw2">sudo</span> <span class="kw2">apt-get install</span> <span class="re5">-y</span> software-properties-common
<span class="co4">you@locatlhost:~$ </span><span class="kw2">sudo</span> add-apt-repository <span class="re5">-y</span> ppa:hvr<span class="sy0">/</span>ghc
<span class="co4">you@locatlhost:~$ </span><span class="kw2">sudo</span> <span class="kw2">apt-get update</span>
<span class="co4">you@locatlhost:~$ </span><span class="kw2">sudo</span> <span class="kw2">apt-get install</span> <span class="re5">-y</span> cabal-install-<span class="nu0">1.22</span> ghc-7.10.3
<span class="co4">you@locatlhost:~$ </span><span class="kw2">cat</span> <span class="sy0">&gt;&gt;</span> ~<span class="sy0">/</span>.bashrc <span class="co2">&lt;&lt;EOF</span>
<span class="co2">you@locatlhost:~$ export PATH=&quot;\$HOME/.cabal/bin:/opt/cabal/1.20/bin:/opt/ghc/7.10.3/bin:\$PATH&quot;</span>
<span class="co2">EOF</span>
<span class="co4">you@locatlhost:~$ </span><span class="kw3">export</span> <span class="re2">PATH</span>=~<span class="sy0">/</span>.cabal<span class="sy0">/</span>bin:<span class="sy0">/</span>opt<span class="sy0">/</span>cabal<span class="sy0">/</span><span class="nu0">1.22</span><span class="sy0">/</span>bin:<span class="sy0">/</span>opt<span class="sy0">/</span>ghc<span class="sy0">/</span>7.10.3<span class="sy0">/</span>bin:<span class="re1">$PATH</span></pre></td></tr></table></div></td></tr></tbody></table></div>Проверяем что все получилось:<br />
<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="169130584"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="169130584" style="height: 142px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
</pre></td><td class="de1"><pre class="de1"><span class="co4">you@locatlhost:~$ </span>ghci <span class="re5">--version</span>
The Glorious Glasgow Haskell Compilation System, version 7.10.3
<span class="co4">you@locatlhost:~$ </span><span class="kw2">mkdir</span> haskell
<span class="co4">you@locatlhost:~$ </span><span class="kw3">echo</span> <span class="st_h">'module Main where</span>
<span class="st_h">main = print &quot;I am alive&quot;'</span> <span class="sy0">&gt;</span> haskell<span class="sy0">/</span>tryit.hs
<span class="co4">you@locatlhost:~$ </span>runhaskell haskell<span class="sy0">/</span>tryit.hs
<span class="st0">&quot;I am alive&quot;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Последнюю стабильную версию Haskell можно узнать пройдя на <a rel="nofollow noopener noreferrer" href="https://www.haskell.org/ghc/download" target="_blank" title="https://www.haskell.org/ghc/download">эту страницу</a><br />
Последнюю стабильную версию Cabal можно узнать пройдя на <a rel="nofollow noopener noreferrer" href="https://www.haskell.org/cabal/download.html" target="_blank" title="https://www.haskell.org/cabal/download.html">эту страницу</a><br />
<br />
<br />
<font size="3">Установка git, nodejs и curl</font><br />
<br />
Делается это всего тремя командами:<br />
<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="962544766"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="962544766" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1"><span class="co4">you@locatlhost:~$ </span><span class="kw2">sudo</span> <span class="kw2">apt-get install</span> <span class="kw2">git</span>
<span class="co4">you@locatlhost:~$ </span><span class="kw2">sudo</span> <span class="kw2">apt-get install</span> nodejs
<span class="co4">you@locatlhost:~$ </span><span class="kw2">sudo</span> <span class="kw2">apt-get install</span> curl</pre></td></tr></table></div></td></tr></tbody></table></div><br />
<font size="3">Установка Elm</font><br />
<br />
Чтобы установить Elm, есть несколько способов:<br />
1) Первый из них - установить с помощью npm(npm - это пакетный менеджер Node.js). Чтобы понять что это за зверь, можно погуглить, либо пройти на <a rel="nofollow noopener noreferrer" href="https://nodejs.org/en/" target="_blank" title="https://nodejs.org/en/">официальный сайт</a><br />
Установка простая(убедитесь что nodejs и npm установлены):<br />
<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="427155575"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="427155575" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1"><span class="co4">you@locatlhost:~$ </span>npm <span class="kw2">install</span> <span class="re5">-g</span> elm</pre></td></tr></table></div></td></tr></tbody></table></div>Чтобы поставить не последнюю версию elm, команда такая:<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="98969777"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="98969777" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1"><span class="co4">you@locatlhost:~$ </span>npm <span class="kw2">install</span> <span class="re5">-g</span> elm<span class="sy0">@</span>0.15.1-beta4</pre></td></tr></table></div></td></tr></tbody></table></div>2) Второй способ мне нравится больше - я его и использую. Сборка из исходников:<br />
Для начала, надо убедиться что в переменной <font color="Red">$PATH</font> прописан путь <font color="red">/usr/local/bin</font>, поскольку при установке будет нужен cabal:<br />
<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="206703028"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="206703028" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1"><span class="co4">you@localhost:~$ </span><span class="kw2">sudo</span> <span class="re5">-s</span>
<span class="co4">root@localhost:~# </span><span class="kw3">echo</span> <span class="re1">$PATH</span>
<span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>sbin:<span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>bin:<span class="sy0">/</span>usr<span class="sy0">/</span>sbin:<span class="sy0">/</span>usr<span class="sy0">/</span>bin:<span class="sy0">/</span>sbin:<span class="sy0">/</span>bin</pre></td></tr></table></div></td></tr></tbody></table></div>Если пути нет, добавим его:<br />
<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="354617484"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="354617484" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1"><span class="co4">root@localhost:~# </span><span class="kw3">export</span> <span class="re2">PATH</span>=<span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>bin:<span class="re1">$PATH</span></pre></td></tr></table></div></td></tr></tbody></table></div>Теперь, надо скачать установщик. Чтобы сразу все было правильно, скопируем установщик в <font color="Red">/usr/local</font>:<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="498179203"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="498179203" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1"><span class="co4">root@localhost:~# </span><span class="kw3">cd</span> <span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>
<span class="co4">root@localhost:~# </span>curl <span class="br0">&#91;</span>url<span class="br0">&#93;</span>https:<span class="sy0">//</span>raw.githubusercontent.com<span class="sy0">/</span>elm-lang<span class="sy0">/</span>elm-platform<span class="sy0">/</span>master<span class="sy0">/</span>installers<span class="sy0">/</span>BuildFromSource.hs<span class="sy0">/</span><span class="br0">&#91;</span><span class="sy0">/</span>url<span class="br0">&#93;</span> <span class="sy0">&gt;</span> BuildFromSource.hs
<span class="co4">root@localhost:~# </span>runhaskell BuildFromSource.hs <span class="nu0">0.16</span></pre></td></tr></table></div></td></tr></tbody></table></div>Какую циферку писать после BuildFromSource.hs, можно узнать на <a rel="nofollow noopener noreferrer" href="https://github.com/elm-lang/elm-platform" target="_blank" title="https://github.com/elm-lang/elm-platform">странице</a> - нужно будет пролистать почти что в самый низ.<br />
При установке, у меня появилась ошибка, говорящая что не установлен пакет zlib1-dev. Установить можно так:<br />
<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="20714425"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="20714425" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1"><span class="co4">root@localhost:~# </span>cabal <span class="kw2">install</span> zlib1-dev</pre></td></tr></table></div></td></tr></tbody></table></div>Прописываем путь до пакетов Elm-платформы:<br />
<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="562477927"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="562477927" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1"><span class="co4">you@localhost:~# </span><span class="re2">PATH</span>=<span class="re1">$PATH</span>:<span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>Elm-Platform<span class="sy0">/</span><span class="nu0">0.16</span><span class="sy0">/</span>bin</pre></td></tr></table></div></td></tr></tbody></table></div>Проверяем:<br />
<br />
<div class="codeblock"><table class="bash"><thead><tr><td colspan="2" id="90615053"  class="head">Bash</td></tr></thead><tbody><tr class="li1"><td><div id="90615053" style="height: 222px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="de1"><pre class="de1"><span class="co4">you@localhost:~$ </span>elm-package <span class="re5">--help</span>
<span class="co4">you@localhost:~$ </span>elm-repl <span class="re5">--help</span>
<span class="co4">you@localhost:~$ </span>elm-make <span class="re5">--help</span>
<span class="co4">you@localhost:~# </span><span class="kw2">mkdir</span> elm
<span class="co4">you@localhost:~# </span><span class="kw3">echo</span> <span class="kw3">echo</span> <span class="st_h">'module Привет where</span>
<span class="st_h">&gt; import Html</span>
<span class="st_h">&gt;</span>
<span class="st_h">&gt; main = Html.text &quot;THIS IS ELM!!!&quot;'</span> <span class="sy0">&gt;</span> elm<span class="sy0">/</span>tryelm.elm
<span class="co4">you@localhost:~# </span><span class="kw3">cd</span> elm
<span class="co4">you@localhost:~# </span>elm-package <span class="kw2">install</span> evancz<span class="sy0">/</span>elm-html
<span class="co4">you@localhost:~# </span>elm-package <span class="kw2">install</span> <span class="re5">-y</span>
<span class="co4">you@localhost:~# </span>elm-reactor</pre></td></tr></table></div></td></tr></tbody></table></div>Теперь можно открыть <a rel="nofollow noopener noreferrer" href="http://0.0.0.0:8000/" target="_blank" title="http://0.0.0.0:8000/">http://0.0.0.0:8000/</a> и посмотреть на первую программу, написанную на Elm.<br />
<br />
<br />
<font size="3">Установка Light Table и плагина</font><br />
<br />
Идем на <a rel="nofollow noopener noreferrer" href="https://&quot;http://lighttable.com" target="_blank" title="https://&quot;http://lighttable.com">сайт</a>, качаем установщик, устанавливаем.<br />
Теперь надо добавить в IDE плагин. Для этого запускаем Light Table и жмем Ctrl+Пробел. Для тех, у кого данное сочетание клавиш занято системой (как в IOS для переключения раскладки), можно открыть через меню (View-&gt;Commands).<br />
Набираем Plugins: Show plugin manager.  <br />
В менеджере плагинов переключаемся на Available и набираем elm<br />
В результатах поиска будет elm-light - его и надо установить - надо навести мышкой на этот плагин и появится кнопка install.<br />
После установки перезагружаем Light Table.<br />
Как пользоваться плагином, я покажу в следующих статьях.  <br />
Если не терпиться, можно посмотреть видео на английском языке:<br />
<a rel="nofollow noopener noreferrer" href="https://&quot;https://www.youtube.com/watch?v=B_eZw_GcM-4" target="_blank" title="https://&quot;https://www.youtube.com/watch?v=B_eZw_GcM-4">Elm Light Table Plugin</a></div>

]]></content:encoded>
			<dc:creator>loothood</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/606805/4069.html</guid>
		</item>
		<item>
			<title>Пятничный Elm. Что такое Elm (Часть I)</title>
			<link>https://www.cyberforum.ru/blogs/606805/4068.html</link>
			<pubDate>Sat, 09 Jan 2016 10:26:09 GMT</pubDate>
			<description><![CDATA[*Пятничный Elm. Что такое Elm (Часть I)* 
 
 
О серии "Пятничный Elm" 
 
Это самый первый пост...]]></description>
			<content:encoded><![CDATA[<div><b><font size="4">Пятничный Elm. Что такое Elm (Часть I)</font></b><br />
<br />
<br />
<font size="3">О серии &quot;Пятничный Elm&quot;</font><br />
<br />
Это самый первый пост серии заметок о языке программирования Elm.<br />
Цель данной серии - дать читателям знания от уровня &quot;Что такое Elm&quot; до &quot;Гуру Elm&quot;, шаг за шагом.<br />
Если вы уже имеете представление об этом языке программирования, можно пропустить эту статью и начать читать следующую.<br />
<br />
<br />
<font size="3">Итак, что же такое Elm? </font><br />
<br />
Elm - будущее веба! Очень скоро фронтенд разработка будет полностью вестись на Elm, так что, если вы хотите угнаться за современными веяниями в области фронтенда, рекомендую вам начать изучать этот язык уже сейчас. Возможно, вы слышали о React и Flux и о том, как круто использовать их в современных реалиях? Забудьте об этом. Elm намного лучше. (Примечание: я никогда серьезно не работал с React или Flux, но слышал довольно много разговоров об этих технологиях, от разработчиков, когда делал кофе на кухне в офисе. Потому считаю что я высококвалифицированный специалист, чтобы делать такие заявления).<br />
Elm - чистый функциональный язык со статической типизацией, который компилируется в JavaScript и HTML. Синтаскисом очень похож на Haskell, что может отпугнуть человека который программирует на JavaScript. Но уверяю вас, вы привыкните довольно быстро.<br />
<br />
<br />
<font size="3">Особенности языка:</font><br />
<ul><li>Чистый, выразительный, легко читаемый синтаксис.</li>
</ul><ul><li>Вывод типов.</li>
</ul><ul><li>Никаких неожиданных падений. Если код прошел компиляцию, вы не увидите ошибок вида &quot;undefined is not a function&quot;. Никогда-никогда. Если программа прошла этап компиляции, она всегда делает именно то, что от нее ожидаешь.</li>
</ul><ul><li>Он по-настоящему быстрый. Утверждается, что он быстрее React. Можно пройти по <a rel="nofollow noopener noreferrer" href="https://evancz.github.io/todomvc-perf-comparison/" target="_blank" title="https://evancz.github.io/todomvc-perf-comparison/">ссылке</a> и убедиться в этом самостоятельно.</li>
</ul><ul><li>Возможность безопасно интегрироваться с чистой JavaScript.</li>
</ul><ul><li>Великолепные тулузы для разработчиков(&quot;живая перезагрузка&quot;, временной отладчик(ориг. &quot; a time-traveling debugger&quot;, и много других).</li>
</ul> <br />
Должен предупредить, что есть один серьезный недостаток Eml: проведя с языком достаточное время, вас будет тошнить от мысли вернуться назад к JavaScript (CoffeScript, TypeScript, …).<br />
<br />
Так же можно посетить <a rel="nofollow noopener noreferrer" href="http://elm-lang.org" target="_blank" title="http://elm-lang.org">официальный сайт</a><br />
<br />
<a rel="nofollow noopener noreferrer" href="https://blog.codecentric.de/en/2015/11/elm-friday-part-01-what-is-elm/" target="_blank" title="https://blog.codecentric.de/en/2015/11/elm-friday-part-01-what-is-elm/">оригинал</a> данной статьи</div>

]]></content:encoded>
			<dc:creator>loothood</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/606805/4068.html</guid>
		</item>
	</channel>
</rss>
