
ДУША прозрачна и тонка...
не разрешайте в ней топтаться...
поверьте, мне, , наверняка...
вся в дырах может оказаться..
и не заклеить, не зашить...
лишь время -лекарь ей поможет..
и РВАНОЙ может она жить...
но, просто ДОВЕРЯТЬ не сможет...
любить не сможет, верить, ждать
и наполняться силой.... тоже..
как решетом воду черпать..
попробуйте...ведь это сложно..
ОНА прозрачна и тонка...
Бывает САМ в нее не лезешь...
Хоть и своя она, ДУША...
Что лишний раз ее бередить...
С чего вы взяли, что познали мою душу?
Что вам доступно то, что скрыто под замком?
Что вам позволено врываться и все рушить,
Переворачивая чувства кувырком?...
С чего вы взяли, что хозяйничать позволю
И наводить \\\"порядок\\\" там на свой манер?
Что уголки вам, потаенные, открою?
Это душа!, а не для выгула вольер..
С чего вы взяли, что являетесь примером?
С чего вы взяли, что должны меня учить
Счастливым мыслям и изысканным манерам:
Как мне дышать, когда грустить, кого любить!?...
Кто дал вам право моей жизнью распоряжаться,
Решая за меня, как поступать?
Вы позабыли, что все могут ошибаться,
И позабыли, что такое помогать...
Ps решила выложить здесь эти стихи.Нашла в интернете.Но они хорошо отражают суть.
ДУША прозрачна и тонка...не разрешайте в ней топтаться...поверьте, мне, , наверняка...вся в дырах может оказаться..и не заклеить, не зашить...лишь [...] читать описание

И внимательно читайте.
Развесёлые частушки -
Как прикол воспринимайте!
Три девицы под окном
Позабылись крепким сном.
А проснулись - в неглиже,
И не девушки уже.
Лишь пустая голова,
Поведётся на ДОМ-2.
За такой, за онанизм,
- Надо ставить 200 клизм!!!
Олигархи, олигархи,
Хризантемочку вам в рот!
До чего же, отморозки,
Задолбали вы народ!
Что ни рожа - пятачок,
Что ни тело - хрюшка.
Что по жизни ни сюжет,
- Пошлая частушка
Если вольно и невольно,
Всех девиц любить подряд,
- Сердцу станет неспокойно,
И душа сорвётся в ад.)))
Ставьте ушки на макушке,И внимательно читайте.Развесёлые частушки - Как прикол воспринимайте!Три девицы под окномПозабылись крепким сном.А [...] читать описание

--- читать описание

--- читать описание

Сейчас сижу и жду завтрашнего дня,естественно немного волнуюсь)
Хочу пожелать всем крепкой семейной жизни,и сам постараюсь не отставать от этих пожеланий.
Пусть через много лет я прочту на сайте то что писал сегодня и вспомню этот момент.
Будьте счастливы.......И любите друг друга.......
Завтра я женюсь,не думал что доживу до этого момента,а ведь мне уже 28 лет .Сейчас сижу и жду завтрашнего дня,естественно немного волнуюсь)Хочу [...] читать описание

Уже скоро) Осталось 15 часов. читать описание

В преддверии весны
Поделись хорошим настроением,
Ничего не требуя взамен.
Пожелай удачи и везения,
И немного ветра перемен.
Всем-всем-всем — не делай исключения! -
Пожелай веселья и добра,
Улыбнись ты солнышку весеннему
И всем людям с самого утра.
Пусть немного радости прибавится
В этом мире сложном, непростом.
Поделись теплом, — а вдруг понравится? -
Не откладывая на потом.)
© Copyright: Арина Забавина, 2013 Свидетельство о публикации №113022708131
Чтобы свернуть горы, необходимы вовсе не горы, а хорошее настроение, жизненная энергия и.стимул.В преддверии весныПоделись хорошим настроением,Ничего [...] читать описание

Когда теряют головы вокруг,
И если ты себе остался верен,
Когда в тебя не верит лучший друг,
И если ждать умеешь без волненья,
Не станешь ложью отвечать на ложь,
Не будешь злобен, став для всех мишенью,
Но и святым себя не назовешь,
И если ты своей владеешь страстью,
А не тобою властвует она,
И будешь тверд в удаче и в несчастье,
Которым, в сущности, цена одна,
И если ты готов к тому, что слово
Твое в ловушку превращает плут,
И, потерпев крушенье, можешь снова -
Без прежних сил - возобновить свой труд,
И если ты способен все, что стало
Тебе привычным, выложить на стол,
Все проиграть и вновь начать сначала,
Не пожалев того, что приобрел,
И если можешь сердце, нервы, жилы
Так завести, чтобы вперед нестись,
Когда с годами изменяют силы
И только воля говорит: \\\"Держись!\\\" -
И если можешь быть в толпе собою,
При короле с народом связь хранить
И, уважая мнение любое,
Главы перед молвою не клонить,
И если будешь мерить расстоянье
Секундами, пускаясь в дальний бег, -
Земля - твое, мой мальчик, достоянье!
И более того, ты - человек!
Стихпросто стих, носмысл его велик. .
О, если ты покоен, не растерян, Когда теряют головы вокруг, И если ты себе остался верен, Когда в тебя не верит [...] читать описание

Как известно каждому уважающему меня человеку, я охладел к использованию Python на смартфоне в качестве годного инструмента прикладного программирования в пользу такой замечательной штуки, как DroidScript. Если вы не знаете что это, то посетите его страничку в Google Play Market и наш кружок юных погромистов-любителей здесь на DV, где до сих пор с переменным успехом теплится тусовка мобильных программистов былинных времен.
Но давайте поближе к стремительно хладеющему телу этого поста.
Поскольку даже самые упоротые фанаты программирования на телефоне признали, что удобнее под него разрабатывать на компьютере, то спешу вас обрадовать: в составе DroidScript из коробки ни много, ни мало WiFi Web Editor (с претензией — впрочем, малообоснованной — на IDE)! Как заметно из названия, предполагается, что телефон будет подключен к компьютеру посредством вайфая. Но у меня его нет. Ситуация осложнялась тем, что я использую Linux Mint как операционную систему. Поэтому я обратился за помощью на форум DroidScript. И один добрый человек мне помог. Привожу его хэлп в неизменном (и непереведенном, я же знаю, что вы все сильны в языках) виде.
Warren Downs
Virtuos86, what Linux distribution do you use? Both WIndows and Desktop-oriented Linux distributions like Ubuntu will automatically treat the Android device as a network connection, if it is plugged in via USB as a \"Media Device\" and you use Android\'s USB tethering mode. Then you don\'t need to mess with ADB settings on Linux (or Windows). But you do still have to check \"Use ADB\" in the DroidScript settings, and connect from a Linux browser to the router address assigned, port 8088.
If you already have ADB set up that may be easier for you, but if not, try the following (Detailed instructions):
1. Plug in Android device to Linux computer via USB.
2. Make sure Media Device is the mode being used.
3. In Android Settings | Wireless and Networks | Tethering & Portable Hotspot, check \"USB tethering\".
4. In Linux, at the command line, type \"route -n\' and you should see a new gateway listed, for example \"192.168.42.129\". This is the address of the Android device as seen from Linux. (It should stay the same every time you plug in).
5. In Android, start DroidScript, go to Settings, and check \"Use ADB\".
6. Also in DroidScript, click the \"up\" arrow to the left of the Droid icon. An \"ADB Connect\" dialog should appear and tell you to navigate to 127.0.0.1:8088 in a browser. You could do that using ADB, but since we\'re using USB tethering, you can instead:
5. In a Linux browser, navigate to https://192.168.42.129:8088 (or whatever address you saw for the gateway in step #4).
Я использовал эти прекрасную подробную инструкцию, и у меня всё заработало. Особенно удобно, что благодаря root и GravityBox, у меня в \"шторке\" есть \"плитка\" для включения \"USB tethering\". Подключил телефон к ЭВМ, тыкнул \"плитку\" (телефон по дефолту настроен на подключение как MTP устройство) и обновил закрепленную вкладку в браузере, — всё, можно творить! Хотя, давайте будем честными, программировать что-то полезное — значит, 99.9% времени отлаживать программу и искать баги, а это очень нервное и нервное дело (забыл еще добавить, что оно нервное).
Оставайтесь на связи, обещаю еще одну запись в этом году или в следующем! Ну, на такой мажорной ноте не грех и попрощаться.
Привет всем! Я как обычно пишу о том, что интересно мне и еще полутора калекам, но делаю это достаточно забавно, так что, если даже вы не из их [...] читать описание

И по квартире в танце покружи!
И танец под волшебные те звуки
Тебя избавит от хандры, тоски и скуки!
*****
Нерадостное настроение радостным заменим!
Не хочется картошки – так свари пельмени!
Не хочется скакать как зайчик по дорожке,
Тогда представь, что цапля ты и стой на левой ножке!
Не хочется еду готовить — не готовь,
Не хочется болеть – пошли подальше боль!
Не хочется смотреть — закрой тихонько глазки!
Не хочешь петь – тогда читай нам сказки!
Захочешь плакать — вмиг мы рассмешим!
Захочешь загрустить — тебе не разрешим!!!
*****
Всякой женщине при муже
Всё равно любовник нужен,
Чтобы мужу на замену
Мог любить в дневную смену.
*****
Когда, взлетев, сорвешься вниз,
Ты за руку мою держись.
Не смей бояться сделать шаг!-
Потом поймешь кто друг, кто враг.
И если вдруг придет беда,
Не унывай ты никогда.
Прошу тебя я не страдать,
И сердце на куски не рвать.
И знай: иди вперед, туда,
Где светит лишь твоя звезда:
Танцуй, играй, шагай, мечтай,
Живи, учись, люби, летай!
И если станет тяжко вдруг
Ты вспомни, что есть рядом друг!
*****
Три девицы под окном
Пили водку, сок и ром.
Лишь одна смогла девица
Без проблем войти в светлицу.
*****
Приготовила еду -
Будет вечер классный!
Я сегодня гостя жду,
Вроде, он согласный.
Познакомились вчера
В чате интернета.
Натрудилась, как пчела,
С самого рассвета.
Стол накрыла: гусь, салат,
Сало, две селедки,
Торт, узбекский виноград
И бутылка водки.
Жду, присела у стола,
Зеркало достала…
Поглядела, поняла -
Водки слишком мало.
*****
Дарите улыбки! Встречайте теплом!
Всегда наполняйте любовью свой дом!
И будут улыбки, тепло и любовь
Назад возвращаться к вам снова и вновь!
И счастье будет на долгие годы!
Ничто не испортит вам Жизни погоды!
Коль грустно, музыку скорей включиИ по квартире в танце покружи!И танец под волшебные те звукиТебя избавит от хандры, тоски и скуки!*****Нерадостное [...] читать описание

Когда ты смотришь в портомоне, Где вместо денег кучка пыли, Не говори с тоскою: \\\"Нет!\\\", Но с благодарностию: \\\"Были!\\\"
Белые каски, красные лица - Отряд пожарных идет похмелиться!
Как повяжешь галстук - береги его. Он ведь от Версачи. Стоит ого-го!
С грязной ложкою в кармане, С лысым кактусом в руке, Я иду на бой с Бабайкой, Что живет на чердаке, Задавлю его я ложкой И заставлю кактус съесть, Я ведь дурочка немножко У меня и справка есть. )))
Если ты с утра проснувшись ощущаешь жажду жизни... Если хочешь дом построить и отправиться в поход... А потом помыть посуду, постирать, пошить, сготовить - Не пугайся, так бывает... Ляг, поспи и все пройдет.
Я оттого не увядаю, И не считаюсь размазнёй, Что если чем-то и страдаю, То исключительно... fигней.
Лечитесь смехом от забот, И от болезней тоже. Он сплетням затыкает рот И смерти корчит рожи. Лечитесь смехом от врагов, Смеяться их учите. Лечите смехом дураков, И умников лечите. Свой смех несмелый, седина, Не смешивай с одышкой: От смеха даже сатана Становится мальчишкой. Нам не приносит ни гроша Безгрешная потеха... Но жизнь чертовски хороша От смеха и до смеха...
Наша Катя не заплачет, Если Катю бросит мальчик! Наша Катя бросит первой, Потому что Катя - Стерва!
Пришла зима - капец прическе! Башка нуждается в расческе! Снял шапку - волосы торчком, Заходишь в офис дурачком!
Если вдруг вам стало грустно - не отчаивайтесь. Черные полосы бывают в жизни каждого человека, а еще им свойственно время от времени чередоваться [...] читать описание

Это плечо и опора во всём, если нужно…
Трезвость ума, малословие, доброе сердце…
С сильным мужчиной душой очень просто согреться…
Слабый мужчина себя украшает слезами…
Плачет всегда, эти жалобы льются часами…
Мир виноватый во всём, все предатели будто…
Только в себе не искали причин почему-то…
Сильный мужчина о женщине плохо не скажет…
В спину других не толкнёт, встречным злом не накажет…
Выдержит боль и найдёт невезений причину…
Всё потому, что является сильным мужчиной…
Слабый мужчина с друзьями жену обсуждает…
Дома жене о друзьях он не лестно вздыхает…
И от проблем, словно страус он голову прячет,
Маску случайно теряя гламурного мачо…
Сильный мужчина поможет не словом, а делом…
Слабый попросит себя пожалеть неумело…
Сильный мужчина прочёл и кивнул, он ведь знает,
Слабый мужчина такие стихи не читает…
Автор:Ирина Самарина-Лабиринт.
Сильный мужчина — не пафосный мачо наружно…Это плечо и опора во всём, если нужно…Трезвость ума, малословие, доброе сердце…С сильным мужчиной [...] читать описание

Как думаете
Здравствуйте добрые люди! Как думаете читать описание

Как видите, я обещал еще один пост в этом году — я сделал. Что ни говори, большой души человек. Но в этот раз ничего не обещаю.
В то время, как на дворе 2017-ый год, я с болью в своем многострадальном сердце вынужден констатировать, что под мобильные устройства по-прежнему [...] читать описание

Как видите, я обещал еще один пост в этом году — я сделал. Что ни говори, большой души человек. Но в этот раз ничего не обещаю.
В то время, как на дворе 2017-ый год, я с болью в своем многострадальном сердце вынужден констатировать, что под мобильные устройства по-прежнему [...] читать описание

- У вас есть воды?
- Не воды, а вода.
- Тогда дайте мне вода!
- Не вода, а воды.
- Да я вижу у вас хрен напьёшся!
https://scontent.xx.fbcdn.net/v/t1.0-9/fr/cp0/e15/q65/17990949_322293198187273_1456236747640985395_n.jpg?efg=eyJpIjoiYiJ9&oh=8b5005253a520caebf4f47c5385700e8&oe=5981BB5F- У вас есть воды?- Не воды, а вода.- Тогда дайте [...] читать описание

Глаза пронзают твои ярким светом.
Так мило, аж в душе моей тепло!
Улыбаясь явилась к миру в этом!
И нам с тобой было так хорошо.
Ты знаешь нашу веру и силу других.
Чуть ближе для меня ты все же стала,
Как куклы Кости в театре теней своих
В явном совершенстве ими овладела
Я оцепенен. И это чья - твоя сила?!
Повадки и толк в граце движенья.
Ты жизнь во мне прежде открыла
И нашел... Совершенное твое тваренье
И снова повторяя твои очертания,
И лишних полу-слов нам не надо.
Славно смеются наши переживания!
Ловлю на мысль нашего взгляда.
Ветер, он Елану звал серенадой.
Дул, четыре флейты ноты с кольяном
Лаская юное тело тонкой прохладой
Мы и так тут закружились этим вальсом
Думаю с выбором бы решиться
Что мне до жадности ласкать
Иногда хочется быстро слиться
Как фото помнить и твой взгляд
В позе, пытаюсь войти в самати
Вечно гулять однажды вне сна
Я прочел тебя, слазь с кровати
Из своего укутонного сукна.
Глаза пронзают твои ярким светом.Так мило, аж в душе моей тепло!Улыбаясь явилась к миру в этом!И нам с тобой было так хорошо.Ты знаешь нашу [...] читать описание

B нoчи yxoдящeгo лeтa,
Kaк бyдтo бы двe пoлoвинки cлилиcь
Paзлoмaннoй дpeвнeй мoнeты.
Kaк бyдтo бы вpeмя для нac иcтeклo
Paздeльнoгo cyщecтвoвaнья.
Haм xoлoднo былo, a cтaлo тeплo,
И пpocтo, кaк пpocтo дыxaньe.
И ктo бы cвидaньeм нaзвaть этo cмoг,
Oшибкoй, любoвнoй нaпacтью -
Двopoвыe кoшки coбpaлиcь y нoг,
Пoгpeтьcя y нaшeгo cчacтья.
Спокойной ночи, и холод за нашим окном.
Не потревожит твоего сладкого покоя.
С три сотни минут и комната белом!
Вот утро... Проснись Моя родная соня!
Kак мы c тoбoй крепко oбнялиcьB нoчи yxoдящeгo лeтa,Kaк бyдтo бы двe пoлoвинки cлилиcьPaзлoмaннoй дpeвнeй мoнeты.Kaк бyдтo бы вpeмя для нac иcтeклoPaздeльнoгo cyщecтвoвaнья.Haм [...] читать описание

Кто без настроения?
Я сейчас тогда начну
Супер-выступление!
Я хочу, чтоб ты быстрей
Просто улыбнулся,
Чтобы к жизни, наконец
Радостной вернулся!
******
Ночь. Улица. Фонарь под глазом
Неясный излучает свет.
А дома ждут – жена-зараза
И.. мать ее!.. исхода нет.
Придешь – начнут опять сначала,
И повторится все, как встарь:
Вновь черпаком куда попало,
Аптечка, йод, второй фонарь
***
О, директор, ты могуч,
Ты гоняешь стаи туч
Заставляешь и в субботу
Выходить нас на работу.
Аль откажешь мне в ответе?
Не видал ли где на свете
Ты зарплаты годовой?
Я ищу ее …
- Постой, есть на севере гора,
В ней глубокая нора,
В той норе на трех канатах
Гроб качается из злата.
В том гробу твоя ЗАРПЛАТА
***
В песочнице дети друг с другом делились,
Кто как и откуда на свет появились.
Виталик со Славиком мямлили грустно,
Что их отыскали на грядке с капустой.
Наташка (откуда взялась?) на вопрос,
Похвасталась важно,что аист принёс.
Но самой крутой стала девочка Света,
Которую папа скачал с интернета
Это кто повесил нос?Кто без настроения?Я сейчас тогда начнуСупер-выступление!Я хочу, чтоб ты быстрейПросто улыбнулся,Чтобы к жизни, наконецРадостной [...] читать описание

Ты мне уже постылым стал!
Как можно столько раз на дню
Лезть в душу белую мою!
Меня уж от тебя тошнит...
Обжора, гад и троглодит!
Обвешай зеркалом меня,
Почаще видеть чтоб себя:
Как отвисает целлюлит,
Как брюхо у тебя торчит,
Щеками уши заслонились,
И зубы от еды сточились,
И вены от натуги вспухли...
Валика, ты, дружок из кухни!
Хоть на денёк меня забудь
Возьми велосипед - и в путь!!
*****
О диете
Перешла сегодня Света
На французскую диету:
Раз в день кекс, и пять раз - секс.
Вот такой деликатес.
Быстро к делу приступила:
Новое белье купила,
Кексик съела, и в кровать –
«Милый, надо жир сгонять!»
Я сгонял, признаюсь честно,
Хоть мне не досталось кекса:
Но за совесть, не за страх
Целый день трудился, ах.
Раз, и два, ещё, и снова…
Мне бы мяса, право слово…
А она пихает в бок:
«Ну, ещё один разок!»
Я бы рад, да силы нету.
Вот бы с хлебушком котлету,
Рюмку красного вина
Осушить сейчас до дна.
Говорю: «Французы, Света,
Перед тем, как делать «это»,
Лишних слов не говоря,
Устриц лупят почём зря.»
А она: «Так ты ж, поганец,
Не француз, не иностранец!
Гречку жрёшь невпроворот.
Ну, давай ещё заход!»
Помогите, ради Бога,
Я едва таскаю ноги:
От диеты от такой
Чуть дышу, едва живой.
Сладко с Зиной было летом.
На фиг я приехал к Свете?
Мучает меня мигрень.
Вот те, чёртик, Юрьев день
Хозяин, ты меня достал!Ты мне уже постылым стал!Как можно столько раз на днюЛезть в душу белую мою!Меня уж от тебя тошнит...Обжора, гад и троглодит!Обвешай [...] читать описание

Посему я принял нелегкое решение продолжать откапывать стюардессу (вы же знаете этот анекдот?) и писать в свой тутошный бложик. Время творить историю.
P.S. Здешние блоги тоже так себе, и весьма, но что поделать.
Я с недавних пор начал изучать язык программирования Rust. Хотелось завести отдельный блог для того, чтобы описывать свои злоключения (а их [...] читать описание

Юмор в том, что \"i32\" это знаковый тип с диапазоном значений от -128 до 127, а индексы в Rust должны быть исключительно положительными. Когда я осознал эту нелепость, я сначала перевел переменные-индексы на использование типа \"u32\", беззнаковых 32-х битных целых. Но здесь вступает другой нюанс. Rust для операции индексации использует значения типа \"usize\". Этот тип платформозависим: на 32-х битных ОС он является аналогом типа \"u32\", на 64-х битных — аналогом типа \"u64\". Это логично, давать возможность использовать максимально большое число для индексации. Rust в операции индексации не приводит автоматически индексы к типу \"usize\", поэтому нужно это делать вручную, что выглядит как:
let v = vec!;
println!(\"{}\", v);
Примечание: если в качестве индекса используется числовой литерал без указания типа, то Rust скомпилирует код, но для его корректности тип литерала выведется как \"usize\", хотя, как я уже отметил выше, по дефолту числовые литералы без указания типа относятся к типу \"i32\":
fn main() {
let index = 1; // при компиляции эта строка будет, условно говоря заменена на \"let index: usize = 1\" или \"let index = 1usize\"
let item = vec!;
println!(\"{:?}\", item);
}
В результате мой код пестрел \"as usize\"-ами. Заменил \"u32\" на \"usize\", стало хорошо. Ну и да, подозреваю, что используй я \"Clippy\", инструмент проверяющий Rust код на наличие \"вредных привычек\" и глупостей, он вероятно обратил бы мое внимание на этот факт.
Как для скриптокодера для меня многое в диковинку в практике программирования на ЯП со статической типизацией. Так меня осенило как-то, что [...] читать описание

Я на время оставил Rust и погрузился в таинство создания Web Extensions под новые версии Firefox. Как известно (мне), Mozilla собралась закопать XUL и старого Файерфокса скоро не станет. Вместе с этим перестанут работать тонны аддонов, которыми, собственно, и был славен этот браузер. Кто-то уже приготовился закапывать "лису", прогнозируя потерю пользовательской базы, но проблема в том, что адекватной замены старым возможностям кастомизируемости среди других популярных браузеров нет, поэтому и бежать особо некуда. Я же бегать не люблю и уже имею в своем активе 2 простеньких (по возможностям, а не по усилиям затраченным на их написание и особенно отладку) дополнения, и одно портированное с Chrome дополнение, которое добавляет определенные приятности в UX. Все эти дополнения предназначены для работы на сайте linux.org.ru, LOR, "информационного ресурса об операционной системе Linux в России".
Что я могу сказать о своих впечатлениях?
Во-первых, оказалось, что когда всю жизнь пишешь синхронный последовательный код, отслеживать и представлять мысленно логику потока исполнения программы, сталкиваясь с асинхронным кодом, не то, чтобы трудно, но приходится ломать шаблоны алгоритмического мышления. Я лично наломал столько шаблонов, что ого-го! Го.
Во-вторых, документация на https://developer.mozilla.org/en-US/Add-ons/WebExtensions достаточно хороша, но некоторые нюансы приходится постигать пошастав по коллекции готовых дополнений, https://github.com/mdn/webextensions-examples (вот она действительно хороша), а некоторые и вовсе после несколькичасового б(з)дения над вроде как рабочим кодом (ну вот, всё по документации делаю, даже код только скопировал и чуть-чуть изменил, что надо-то, а?!). Тем не менее, что хотел, то сделал, а значит я молодец делать дела с Web Extension API можно. Кстати, благодаря тому, что Chrome также поддерживает Web Extension API, как и Opera (строго говоря, в документации для многого прямо указано, что это скопировано с Chrome API), если у вас есть на примете дополнения с Хрома, которые вы бы хотели перетащить в Огнелис, то вероятно это вполне осуществимая затея.
Я на время оставил Rust и погрузился в таинство создания Web Extensions под новые версии Firefox. Как известно (мне), Mozilla собралась закопать XUL и старого [...] читать описание

Вторым же и куда более неприятным затруднением явилась регрессия, наметившаяся в кодовой базе. А если просто, по пацаночке, то игра стала падать при определенных действиях. А значит, надо дебажить.
В общем, долго ли, коротко, а несколько дней назад я открыл проект, окинул горделивым взором килобайты вершины погромистской деятельности своей, потом переключился в "полуночный командир", которым я по недоразумению пользуюсь как файловым менеджером на линуксе, запустил свою игрулю и убедился, что она падает столь же исправно.
Погрустив с минутку, я было ринулся расставлять println'ы aka отладочную печать, а потом подумал, что было бы неплохо использовать такую штуку из Python мира, как декораторы, для облегчения своей доли. То бишь повесил на нужную функцию декоратор, реализующий отладочную печать, скажем, при установленном флаге "DEBUG = true;" при вызове обернутой им функции, и всё, не надо добавлять строчки с принтами, а потом их удалять, когда будут не нужны. К тому же Rust это язык со статической типизацией, а значит, можно сделать так, чтобы декораторы навешивались при включенном флаге отладки во время компилирования, то есть с минимальным оверхедом.
Ребят, если бы я знал, в какую жопу лезу, я бы передумал. Вот я отвечаю.
Но, но, но. Я всё-таки это сделал и сделал, надеюсь хорошо. Поэтому горд неимоверно. И ничего страшного, что на Python декораторы реализуются за 5 минут, просто потому что они уже фактически доступны искаропки, благодаря возможностям языка, а я потратил 5 дней, сражаясь аки лев с конпелятором Rust, и исписав двести строк программного кода (в основном там разбор AST определения функции).
Конечно, пока реализованы не все возможности питоньих декораторов, например, декораторы с добавочными аргументами или декораторы структур и типажей (хотя тут подозреваю, я надорвусь, если возьмусь делать). Но основа: взять функцию и подменить ее обёрткой, — сделана, и этим можно пользоваться. А вот и ссылка на репозиторий: https://github.com/Virtuos86/rust-decorators
А теперь можно и приступить к отладке "рогалика". О боже, дай мне сил…
У меня наметилась лишняя неделя безработицы недавно, поэтому устав пялиться в Веб 2.0, я внезапно вспомнил, что программист. Открыл проект [...] читать описание

Я пишу код на Rust, используя некогда хипстерский редактор Sublime Text, в данный момент плавно переполз на 3-ю версию со 2-ой. Теперь на звание хипстерских поделок претендуют поделки на базе Electron типа VSCode и Atom, а юзеры "саблайма" благополучно перешли в разряд степенных, не бегущих за меняющейся модой серьезных людей .
Работать с Rust кодом помогает плагин `Rust Enhanced`. Помимо надоедливой проверки корректности кода, которая поглощает мои нервные клетки с аппетитом голодной гиены — потому что я обычный быдлокодер, а Rust — очень сложный для нашей братии, — так вот, помимо этого плагин предоставляет несколько режимов для сборки готового кода, от обычной компиляции до запуска тестов/бенчмарков/сборки документации/приготовления кофе/и чего-то ещё.
Но! Но я столкнулся с тем, что при неудачной сборке получаю слишком мало деталей и подробностей. По счастью, `rustc` очень дружелюбный и посоветовал мне использовать ключ `--verbose` для сборки.
Вывод ясен — нужен свой сборочный сценарий. Сказано — сделано.
Выбираем в панели меню пункт `Tools`. Далее `Build System` -> `New Build System...`
Открывается новая вкладка редактора с заготовкой:
{
"shell_cmd": "make"
}
Изменяем на:
{
"shell_cmd": "RUST_BACKTRACE=1 cargo run --verbose"
}
Дальше сохраняем:
Теперь идем по знакомому пути `Tools` -> `Build System` и выбираем свою систему сборки вместо `RustEnhanced`. Теперь в случае проблемной компиляции можно будет увидеть необходимые подробности.
Спасибо за внимание.
Здравствуйте. Я пишу код на Rust, используя некогда хипстерский редактор Sublime Text, в данный момент плавно переполз на 3-ю версию со 2-ой. Теперь [...] читать описание

Вот. Одна беда — мне надо для ST3, а для него темы это целые пакеты с ресурсами, а здесь можно скачать только голый XML-документ. Зато реально [...] читать описание

Я нашел причину падений своей игры. А вот и виновник торжества:
pub fn GenerateMonsters() {
let mut v = vec!();
for mt in MonsterTypes.iter() {
if (mt.Level == unsafe {map::CUR_MAP as u32}) && map::random(0, 6) == 0 { // проблемная строчка
v.push(*mt);
};
}
for i in 0..MaxMonsters - 1 {
let mut m: TMonster = v;
let (x, y) = map::FreeMapPoint(get_ref_curmap!());
m.x = x;
m.y = y;
unsafe { MONSTERS = m; }
}
}
Как говорится в одном старом анекдоте, \"на третий день томящийся в плену индеец Зоркий Глаз заметил, что в сарае, куда его заперли, нет одной стены\". Суть в том, что условие \"map::random(0, 6) == 0\" с вероятностью 5/6 не выполнится ни для одного \"mt\", а значит массив \"v\" останется пустым. А потом я передаю в функцию по сути два нуля, потому что длина пустого массива равна нулю: \"map::random(0, v.len())\"
Функция \"random\" определена так:
pub fn random(start: usize, end: usize) -> usize {
use rand::{thread_rng, sample};
if end
У меня есть две новости, плохая и хорошая. Но поскольку вас их эмоциональная окраска не касается, то начну с любой.Я нашел причину падений [...] читать описание

Предназначен syn именно для парсинга исходного кода на Rust. Вот так раз. Как раз что мне нужно. К сожалению, он у меня почему-то установился криво, потому что половина функций не импортируется, когда я попытался создать тестовый проект. Разбираться мне было некогда, но понятно, что когда я захочу переписать свою библиотечку декораторов, этим придется заняться. Пока же я переключаюсь на игру.
Как я и обещал — а я всегда держу обещания, когда мне это выгодно — пишу о том, что моими растовыми декораторами пользоваться можно, но осторожно. [...] читать описание

Во-первых, в огнелисе для доступа к API используется корневой объект `browser`, в то время как Chrome в качестве такового использует `chrome`. Во-вторых, несмотря на идентичное API, существует разница и в способе его использования: в Хроме нужно передавать в функции API (методы chrome) колбэки, что провоцирует COP — колбэк-ориентированное программирование, в то время как Файерфоксе функции API возвращают промисы, что, на мой взгляд, гораздо удобнее.
Когда я обнаружил эти отличия, я немного приуныл, поскольку это означало, что при портировании дополнения между браузерами его либо придется переписывать самым обезьянним образом, либо изначально городить диспатчинг.
Но когда зарелизился FF 57, я в ходе разработки обнаружил, что в Файерфоксе заработал и объект `chrome`. К сожалению, я не проверил, является ли он обычным алиасом к `browser` или он копирует поведение хромовского оригинала и позволяет работать с ним с использованием колбэков, а не промисов. Если это так, то это бы значительно упростило портирование дополнений с Хрома в Файерфокс.
Пустяковое замечание, но для истории полезно.
Когда революционная версия 57 еще пребывала в статусе beta, а я начинал делать адд-оны к \\\"огнелису\\\", я столкнулся с тем, что зачастую в примечаниях [...] читать описание

Мой вольный авторский перевод заинтересовавшего меня поста, который я прочитал, просматривая свежий выпуск \"Неделя в Rust\". Оригинал можно найти здесь. Но лучше прочитать мой перевод.
Давным давно, Rust был языком с типовыми состояниями. Официально типовые состояния были выкинуты задолго до Rust 1.0. В этом тексте я раскрою вам секретный секрет сообщества Rust: в Rust по-прежнему есть типовые состояния. БА-ДУМ-ТССС!
Секундочку, а что такое \"типовое состояние\"?
Рассмотрим объект, представляющий файл — давайте обозначим его структурой данных MyFile. До того момента, как MyFile будет открыт, он не может быть прочитан. В случае если MyFile закрыт, он также не может быть прочитан. Между двумя этими состояниями файл может быть прочитан. Типовые состояния это механизм, дающий тайпчекеру возможность проверить, что вы не делаете следующих ошибок:
fn read_contents_of_file(path: &Path) -> String {
let mut my_file = MyFile::new(path);
my_file.open(); // Ошибка: эта операция может завершиться неудачно.
let result = my_file.read_all(); // Невалидно, если `my_file.open()` завершилось неудачно.
my_file.close();
my_file.seek(Seek::Start); // Ошибка: `my_file` уже закрыт.
result
}
В этом примере мы сделали две ошибки:
1. мы прочитали файл, который может не быть открытым;
2. мы установили текущую позицию чтения в файле, который уже был закрыт.
В большинстве языков программирования мы легко можем спроектировать API MyFile так, чтобы быть уверенными, что первая ошибка будет невозможной, просто бросая исключение, когда файл не получается открыть. Некоторые стандартные библиотеки и рамки решают не следовать этому принципу ради гибкости, но возможности существуют в самом языке.
Вторую ошибку намного сложнее перехватить. Большинство ЯП поддерживают необходимые возможности, чтобы сделать эту ошибку сложной для воспроизведения, как правило, закрывая файл при уничтожении или в конце вызова функции высокого порядка, но единственный неакадемический язык, о котором я знаю, который может фактически полностью предотвратить эту ошибку, это Rust.
Тривиальные типовые состояния в Rust
Итак, как мы делаем это в Rust?
Простейший способ сделать это — ввести здоровые типы (ради Бога, если знаете более приличный перевод термина \"sane types\", сообщите мне) для наших операций над MyFile:
impl MyFile {
// `open` это единственный способ создания экземпляра `MyFile`.
pub fn open(path: &Path) -> Result { ... }
// `seek` требует экземпляр `MyFile`.
pub fn seek(&mut self, pos: Seek) -> Result { ... }
// `read_all` требует экземпляр `MyFile`.
pub fn read_all(&mut self) -> Result { ... }
// `close` принимает аргумент `self`, не ссылки `&self` или `&mut self`,
// который означает, что этот метод *перемещает* свой объект, эффективно поглощая его.
pub fn close(self) -> Result { ... }
}
impl Drop for MyFile {
// Определяем деструктор для автоматического закрытия экземпляра `MyFile`,
// если мы еще не закрыли его.
fn drop(&mut self) { ... }
}
Давайте перепишем наш изначальный пример:
fn read_contents_of_file(path: &Path) -> Result {
let mut my_file = MyFile::open(path)?;
// Обратите внимание на `?`. Это простой оператор, который просит
// компилятор проверить успешность выполнения операции.
// *Единственный* способ получить экземпляр `MyFile`
// это иметь успешно завершенным `MyFile::open`.
// В этой строке `my_file` это объект `MyFile`,
// который можно использовать.
let result = my_file.read_all()?; // Корректно.
my_file.close(); // Корректно.
// Поскольку `my_file.close()` поглощает `my_file`,
// эта переменная больше не существут.
my_file.seek(Seek::Start)?; // Ошибка, которую обнаружит компилятор.
result
}
Это работает и в более сложных случаях:
fn read_contents_of_file(path: &Path) -> Result {
// Аналогично.
let mut my_file = MyFile::open(path)?;
let result = my_file.read_all()?; // Корректно.
if are_we_happy_yet() {
my_file.close(); // Корректно.
}
// Поскольку `my_file.close()` поглощает `my_file`,
// эта переменная больше не существует, по крайней мере,
// в данной ветви выполнения кода.
my_file.seek(Seek::Start)?; // Ошибка, которую обнаружит компилятор.
result
// Если мы не закрыли `my_file`, то по выходе из блока кода,
// в котором мы его определили (в данном случае, это тело функции),
// здесь сработает его деструктор, который закроет файл.
}
Ключевой момент заключается в том, что система типов Rust обеспечивает соблюдение того факта, что переменная не может быть использована после перемещения. В нашем случае my_file.close() переместил значение, эффективно поглотив его.
Даже если бы мы попытались скрыть переменную где-то в другом месте и повторно использовать её после вызова my_file.close(), эта попытка была бы пресечена компилятором:
fn read_contents_of_file(path: &Path) -> Result {
// Аналогично.
let mut my_file = MyFile::open(path)?;
let result = my_file.read_all()?;
let mut my_file_sneaky_backup = my_file;
// Здесь мы переместили `my_file` в `my_file_sneaky_backup`.
// Поэтому мы не можем больше использовать.
my_file.close(); // Ошибка, которую обнаружит компилятор.
my_file_sneaky_backup.seek(Seek::Start)?;
result
// Если мы не закрыли `my_file`,
// здесь сработает его деструктор, который закроет файл.
}
Давайте испробуем иной путь, чтобы обмануть компилятор, для доступа к файлу после его закрытия:
fn read_contents_of_file(path: &Path) -> Result {
let my_shared_file = Rc::new(RefCell::new(MyFile::open(path)?));
// Здесь `my_shared_file` это shared указатель на мутабельный
// экземпляр `MyFile`, наподобие обычной
// ссылки в Java, C# или Python.
let result = my_shared_file.borrow_mut()
.read_all()?; // Корректно.
let my_shared_file_sneaky_backup = my_shared_file.clone();
// Мы клонировали указатель, создав второй способ доступа к `my_shared_file`.
// Давайте удостоверимся, что мы можем использовать бэкап
// и оригинальный файл:
my_shared_file_sneaky_backup.seek(Seek::Start)?; // Корректно.
my_shared_file.seek(Seek::Start)?; // Также корректно.
// Ха-ха, теперь-то мы, конечно, можем закрыть `my_shared_file`,
// а потом манипулировать `my_shared_file_sneaky_backup`,
// словно мы в Java, C# или Python!
// Да вот беда, мы не можем вызвать `my_shared_file.close()`,
// потому что укрытый `MyFile` разделен (shared),
// что означает, что никто не может *перемещать* его.
my_shared_file.close(); // Ошибка, которую обнаружит компилятор.
my_shared_file_sneaky_backup.seek(Seek::Start)?;
result
// Если мы не закрыли `my_file`, деструктор закроет его здесь.
}
И снова наши поползновения были пресечены компилятором. В самом деле, если явно не перейти в unsafe режим, мы не сможем разбить инвариант, в котором seek не может быть использован после закрытия.
Этот пример демонстрирует первый кирпич типовых состояний в Rust: типизированную операцию перемещения. Но мы разобрались только с тривиальным случаем, в котором файлы имеют лишь два состояния: открыт и закрыт.
Давайте посмотрим, как мы можем управиться с более сложными случаями.
Сложные типовые состояния
Вместо файлов, давайте теперь рассмотрим следующий (и, по общему признанию, довольно тупой) сетевой протокол:
1. Отправитель отправляет сообщение \"HELLO\".
2. Приемник получает сообщение \"HELLO\", отвечает сообщением \"HELLO, YOU\".
3. Отправитель получает сообщение \"HELLO, YOU\", отвечает случайным числом.
4. Получатель получает номер от отправителя, отвечает тем же номером.
5. Отправитель получает одинаковое количество от приемника, отвечает \"BYE\".
6. Получатель получает \"BYE\" от отправителя, отвечает \"BYE, YOU\".
7. Вернитесь к 1.
Любое другое сообщение игнорируется.
Мы можем спроектировать нашего Отправителя (и аналогично Получателя) так, чтобы гарантировать, что операции выполняются в правильном порядке. На данный момент мы не заботимся об идентификации корреспондента или числа.
Для этой цели мы объединим типовые состояния с другим методом, хорошо известным функциональным программистам, таким как фантомные типы.
// Серия типов нулевого размера (нет полей => нет состояния => в рантайме не существуют),
// представляющих состояние отправителя.
// Значение не имеет значения, только тип
// (отсюда и название \"фантомный тип\").
struct SenderReadyToSendHello;
struct SenderHasSentHello;
struct SenderHasSentNumber;
struct SenderHasReceivedNumber;
struct Sender {
/// Актуальная реализация сетевого I/O.
inner: SenderImpl;
/// Поле нулевого размера, не существующее во время выполнения.
state: S;
}
/// Следующие методы могут быть вызваны независимо от состояния.
impl Sender {
/// Порт, используемый для подключения отправителя.
fn port(&self) -> usize;
/// Закрыть отправителя, раз и навсегда.
fn close(self);
}
/// Следующий метод может быть вызван только в состоянии SenderReadyToSendHello.
impl Sender {
/// Отправить приветствие.
///
/// Этот метод поглощает отправителя в его текущем состоянии
/// и возвращает его в новом состоянии.
fn send_hello(mut self) -> Sender {
self.inner.send_message(\"HELLO\");
Sender {
/// Перемещаем реализацию сетевого I/O.
/// Компилятор достаточно умён,
/// чтобы понять, что это не требует никакой рантайм-операции.
inner: self.inner,
/// Заменяем поле нулевого размера.
/// Эта операция будет вычищена во время выполнения.
state: SenderHasSentHello
}
}
}
/// Следующий метод может быть вызван только в состоянии SenderHasSentHello.
impl Sender {
/// Ждать, пока получатель не отправит \"HELLO, YOU\",
/// ответить числом.
///
/// Вернуть отправитель в состоянии `SenderHasSentNumber`
fn wait_respond_to_hello_you(mut self) -> Sender {
// ...
}
/// Если получатель отправляет \"HELLO, YOU\", ответить числом и
/// вернуть отправитель в состоянии `SenderHasSentNumber`.
///
/// Иначе вернуть неизмененное состояние.
fn try_respond_to_hello_you(mut self) -> Result {
// ...
}
}
/// Следующий метод может быть вызван только в состоянии SenderHasSentNumber.
impl Sender {
/// Ждать, пока получатель не отправит число, ответить \"BYE\".
///
/// Вернуть отправитель в состоянии `SenderReadyToSendHello`
fn wait_respond_to_hello_you(mut self) -> Sender {
// ...
}
/// Если получатель отправляет число, ответить и вернуть отправитель
/// в состоянии `SenderReadyToSendHello`.
///
/// Иначе вернуть неизмененное состояние.
fn try_respond_to_hello_you(mut self) -> Result {
// ...
}
}
Из этого дизайна очевидно, что Отправитель может следовать только такому протоколу:
1. из шага 1 (SenderReadyToSendHello) он может идти только к шагу 3;
2. из шага 3 (SenderHasSentHello) он может только либо оставаться на шаге 3 или идти к шагу 5;
3. из шага 5 (SenderHasSentNumber) он может только либо оставаться на шаге 5 или идти к шагу 1.
Любая попытка нарушить протокол будет заблокирована системой типов.
Если вам когда-нибудь понадобится работать с сетевыми протоколами, драйверами устройств, промышленными устройствами со специфичными инструкциями безопасности или OpenGL/DirectX/чем угодно еще, что потребует от вас выполнения сложных взаимодействий с \"железом\", вы определенно будете счастливы иметь такие гарантии!
Добро пожаловать в мир типовых состояний.
Краткое примечание: за типовые состояния
Продолжая наш сетевой пример, что если мы захотим, скажем, сохранять число, отправленное сервером, чтобы проверить, что означает ответ? Чтобы сделать это, мы можем сохранять число в SenderHasSentNumber:
struct SenderHasSentNumber {
number_sent: u32,
}
И снова, компилятор будет проверять, что код получает доступ к number_sent, только когда отправитель находится в состоянии SenderHasSentNumber.
Мы потеряем (крошечный) объем производительности, компилятор не сможем оптимизировать трансформацию Отправителя между идентичными представлениями, но вообще это того стоит.
Ти́ повые состояния (`typestates`) in RustМой вольный авторский перевод заинтересовавшего меня поста, который я прочитал, просматривая свежий [...] читать описание

Я зашел туда сегодня, чтобы почитать что-нибудь нового в блоге \\\"Rust\\\", хаб \\\"Программирование\\\". Нашел много чего, в частности и переведенный мною недавно материал про типовые состояния. Но ничего оригинального, одни переводы. С*ка, хоть \\\"крестики-нолики\\\" напишите, да расскажите об этом, лишь бы контент был уникальный. Нет, это не значит, что никто не делает с помощью Rust ничего оригинального и интересного. Но популяризовать тоже надо уметь и желать.
Все мы знаем, что такое Хабрахабр, Хабр, Хабра и т.д. А если вы не знаете, то идите отсюда — здесь неинтересное рассказывают.Я зашел туда сегодня, [...] читать описание

Из плюсов: в настройках (открываем страницу установленных дополнений по Ctrl+Shift+A или через пункт в меню браузера и ищем мое дополнение) можно указать, какую именно папку с закладками открывать (все же в курсе, что закладки необязательно сваливать в одну кучу, а предусмотрительнее распихивать их по смыслу в разные папки?), а также задавать css-стиль для оформления списка с закладками, что позволяет настроить цвета, размер и шрифты в списке. Удобно, не правда ли?
Зачем оно надо, если в браузере искаропки есть возможность поместить на ту же панель штатную кнопку с закладками, еще и более фичастую? Я не знаю
Есть у меня на AMO (addons.mozilla.org) дополнение для Firefox Quantum (Firefox >= 57.0), My Clean Bookmarks. Ничего особенного, добавляет на панельку, находящуюся справа от [...] читать описание

Для получения результата идем по вложенным пунктам панели меню: Tools > Build System > New Build System…
Открывается новая вкладка с заготовкой конфига новой сборочной системы. Заменяем её на следующий код:
{
\"cmd\": ,
\"selector\" : \"./source.c\",
\"shell\": true,
\"working_dir\" : \"$file_path\",
\"variants\" :
},
{
\"name\": \"Compile && Run\",
\"cmd\" :
},
]
}
Теперь сохраняем файл (Ctrl+S) в той директории, в которой откроется файловый диалог, под любым именем, главное, оставить расширение `.sublime-build`. Далее закрываем за дальнейшей ненадобностью вкладку с конфигом (Ctrl+W), переходим к исходнику, Tools > Build System > %наша_сборочная_система_для_C%.
Но это еще не все. Нажав Ctrl+Shift+B, мы увидим список команд. Это команды, описанные в конфиге. Первая — это корневая \"cmd\", остальные — перечисленные по порядку варианты из \"variants\". В нашем случае названия говорят сами за себя, разберетесь. Выбранная единожды, команда запоминается и далее будет доступна по \"прямому\" шоткату Ctrl+B.
Да, забыл оговорить, что конфигурация предназначена для ОС GNU/Linux, на Windows понадобится указывать параметр \"path\", путь к исполняемому файлу компилятора, а также еще какие-то меры.
===========================================================================================
Update (от 8 мая)
Cargo прекрасная вещь, что касается работы с проектами. Но что делать, если нам не нужен проект, а нужно набросать небольшую программку? Раньше я, чертыхаясь, создавал на скорую руку полуанонимный проект, наспех заполнял Cargo.toml, и только после всей этой бюрократии мог писать и тестировать код. Недавно я увидел в одном тьюториале хорошую идею и написал еще одну сборочную команду.
Назовём её RustScript:
{
\"shell_cmd\": \"rustc $file_name && $file_base_name\"
}
Запускаем компилятор Rust и передаем ему полное имя исходника для компиляции, а затем запускаем получившийся исполняемый файл, чье имя будет именем исходника без расширения \".rs\"
Всё!
Понадобилось мне сегодня потыкать сорец написанный на ЯП Си. Потыкать и пособирать, проверяя его работоспособность. Как я уже писал, для кодинга [...] читать описание

Но когда напишу, будет интересно, обещаю.
Пишу уже вторую неделю урывками большой пост про касты и приведения в Rust, хотя информация оказалась в некотором роде не привязана к конкретному [...] читать описание

И вот теперь у меня появилась робкая надежда положить конец этим терзаниям. Тема довольно объемная, поэтому я разобью её обзор на несколько постов. Итак, приступим.
Знаете ли вы, что такое \"абстракция\"? Зачастую нам приходится иметь дело со сложной и плохо усваиваемой информацией, причем связанной между собой, поэтому её желательно поглощать пусть и по кускам, но системно. А умишко-то невелик! О чём, кстати, предупреждал ещё Козьма Прутков, глаголя, что нельзя объять необъятное. Поэтому давным-давно для преодоления этого затруднения принято использовать анализ, который позволяет увидеть за нагромождениями хаоса чёткие контуры главенствующей идеи, которая всем этим заправляет. Не всегда выявление этого сравнительно компактного ядра возможно, порою приходится использовать допущения, чтобы втиснуть всю информацию в задуманное нами прокрустово ложе, но итоговый результат того стоит, поскольку сия идея задумывается и является ключом к пониманию обозреваемой проблемы. Так вот, эта исключительно умозрительная конструкция и называется абстракцией. Кто-нибудь что-нибудь понял? Нет, ну да не беда, это и не было целью.
Главное понять, что грамотная абстракция позволяет усвоить информацию практически любого уровня сложности. Пример популярной абстракции — пресловутый \"кот Шредингера\".
Я долго размышлял над тем, какую абстракцию было бы удобно использовать для понимания сути кастования, каста. Примерно 1 час. Очень долго, согласитесь. И нашёл! Таковой абстракцией являются МНОЖЕСТВА. Я не помню математического определения сей субстанции из теории множеств, поэтому буду использовать упрощенное описательное. Множество состоит из элементов, но может быть и пустым. Множество может содержать подмножества; фактически любое множество содержит бесконечное число подмножеств, учитывая оговорку выше про пустые множества, поскольку множество пустых множеств не содержит ни одного элемента. Можно представить множества как сита с ячейками разного размера и формы, параметры ячеек описывают критерии отбора в множество: чем меньше ячейки и изощреннее форма, тем меньше элементов попадает в множество. Все эти смысловые экзерсисы, впрочем, нам не особенно нужны, мы и так не раз имели дело с пустыми множествами наличных денег и туалетной бумаги, и можем смело утверждать их небольшую практическую ценность. Итак, мы имеем, что:
• множество = подмножество_1 + подмножество_2 + … + подмножество_N
• множество = элемент_1 + элемент_2 + … + элемент_N
Запомнили и идём дальше.
Сразу — ага, через несколько абзацев от начала — обозначу два ключевых понятия:
• cast, casting — преобразование;
• coercion — приведение (не путать с ghost, привидением то бишь).
В дальнейшем я буду использовать эти понятия в их русском переводе, потому что это позволит их удобно склонять и создавать производные слова, но вы не затруднитесь напоминать себе англоязычные термины, которые за ними стоят.
Преобразование отвечает на вопрос \"что?\" ( \"что делать?\"), приведение расскажет, \"как\" это происходит. Преобразование указывает программист, привидение (чёрт, я и сам склонен ошибаться!) производит компилятор. Приведение валидно и допустимо, если удовлетворяет правилам приведения. Их много, и их все фиг запомнишь, но вы не расстраивайтесь: в случае чего, компилятор, как и всегда, оплюет вас стэктрейсом, который принесет с собой искру истины в виде сообщения об ошибке. Подробно правила приведения я разберу в следующих постах, которые войдут в открытое этим текстом множество постов о приведениях и преобразованиях (видите, как я ловко проверил вас на предмет усвоения изложенного материала?).
Главная пуанта заключается в том, что приводить элементы одного множества к элементам другого множества можно только в том случае, если эти множества являются подмножествами более общего множества.
Числовые преобразования
Закрепим и завершим первый пост рассмотрением преобразования чисел.
Удивительным образом числовые типы, соответствуя в плане семантики математическим числам, обладают таким свойством, как и различные подмножества всех действительных чисел. Поэтому будет достаточно просто привести пример на основе приведения экземпляров .
Таким образом, для закрепления, когда у вас возникает необходимость представить объект одного типа как объект другого типа, то вы указываете необходимость преобразования, а компилятор производит приведение, согласно правилам приведения. У приведения НЕТ синтаксиса, это строго вотчина компилятора. У преобразования синтаксис имеется, это бинарный оператор as:
let x = +1i8 as u8; // читается это как угодно, один из вариантов: \"элемент `1` из множества знаковых 8-битных чисел представить как аналогичный элемент из множества беззнаковых 8-битных чисел\"
Обратите пристальное внимание на мой комментарий. Как вы догадались, он не просто так написан. Согласно Чехову, висящее на стене ружье обязано выстрелить, и вот наша абстракция совершает пробную пристрелку.
Почему я записал 1 как +1? Знаковый числовой тип потому и знаковый, что его экземпляры имеют знак, указывающий по какую сторону от нуля на числовой оси они находятся, в области отрицательных чисел или же в области положительных чисел. Но в синтаксисе языков программирования принято то же допущение, что и в математике: у положительных чисел знак можно не указывать, потому что он не несет семантического значения (как и в жизни хорошим ребятам прощаются некоторые вольности просто потому, что они положительные). Но об этом не нужно забывать.
Как мы знаем, тип i8 является множеством, охватывающим … а сколько чисел он охватывает? Давайте посчитаем. i8 => для описания требуется 8 битов; каждый бит может иметь 2 значения: 0 или 1 (двоичная система счисления, дамы и господа!), отсюда, используя комбинаторику, получаем размер множества из формулы 2^8 = 256, то есть двойка в восьмой степени. Можно записать и по-другому, используя операцию побитового сдвига:
1 << 8 даёт 256
И как же располагаются эти 256 чисел? От -128 до +127, включая 0 как первый положительный элемент.
В то же время множество элементов типа u8 заключает в себе также 256 чисел, но поскольку тип беззнаковый, то числа эти исключительно положительные с добавлением нуля, то есть диапазон от 0 до 255.
И каким же образом мы можем преобразовать элементы из одного диапазона в элементы из другого диапазона? Здесь нужно вспомнить о свойстве, не присущем числам, но присущем числовым типам при преобразованиях: они кольцевые. В то время, как мат. числа находятся в диапазоне от -∞ до +∞, числовые типы данных, во-первых, не могут рассчитывать на такую роскошь ввиду того, что компьютерная память всегда ограничена какими-то конкретными пределами, а во-вторых, по большей части и не нуждаются в этом. Как мы уже выяснили выше, такой тип, как i8, охватывает всего две с половиной сотни значений. Но что же происходит, когда в результате операций мы выходим за границы диапазона числового типа? Оказывается, границы дипазона \"соединены\" друг с другом так, что диапазон образует кольцо, с тем лишь нюансом, что границы не совпадают, а идут друг за другом: +255_u8 + 1 даст 0_u8, -128_i8 - 1 даст +127_i8. То есть, если мы выходим из диапазона за пределы одной границы на N единиц, то этим самым входим в диапазон со стороны другой границы на N - 1 единиц.
Кстати, в Rust есть compile-time проверка выхода за пределы диапазона для числовых типов (это еще часто называется \"переполнением\") для констант (во всяком случае, работает она на этапе синтаксического анализа), поэтому примеры, которые я указал выше, наподобие +255_u8 + 1, не скомпилируются. Для успешной компиляции их нужно переписать с использованием промежуточной переменной:
fn main() {
let a = +255_u8; // правая граница диапазона типа `u8`
println!(\"{:?}\", a + 1);
}
// выведет: 0 — левая граница диапазона типа `u8`
Вернемся же к поставленному ранее вопросу: каким же образом мы можем преобразовать элементы из одного диапазона в элементы из другого диапазона?
Идентификаторы числовых типов в Rust состоят из двух составляющих: категории и размера в битах. Первая обозначается символом, например, \"i\" в \"i32\", второй числом, например, \"16\" в \"u16\".
Итак, у нас есть число a типа CN (категории C, размера N), которое мы хотим преобразовать в число a1 типа C1N1 (категории C1, размера N1). Какими правилами приведения руководствуется компилятор при таких исходных (здесь мы резко переходим от моего словесного скоморошества к сухому и беспристрастному изложению документации):
Вы должно быть помните, что тыщей строк ранее я объяснял про объединение границ диапазона для его закольцовывания. На практике это трансформируется в следующее: остаток от деления исходного числа a на размер дипазона типа итогового числа a1, т.е. C2N1, в который оно преобразуется, даст нам число a1. Разумеется, если N меньше N1, то ничего переводить и не надо, ибо a1 = a, поскольку больший диапазон включает меньший диапазон той же категории. Также можно заметить, что никаких действий не нужно производить, если a меньше длины диапазона типа C1N1, поскольку нацело на него не делится и само по себе является искомым остатком. Нас интересуют все остальные случаи. Преобразование 257_u16 as u8 после вычисления 257 % 256 даст 1_u8, что нам и нужно.
• C != C1, N == N1 (i32 -> u32): преобразование между двумя целыми одинакового размера является \"нулевой операцией\", NOP. В это трудно поверить, но для подобного преобразования компилятору достаточно сменить у числа метку типа с исходного на конечный, и всё, но это будет сделано в compile-time, а для рантайма будет сгенерирована инструкция NOP, которая, естественно, будет удалена в ходе оптимизаций.
Давайте попробуем разобраться в сути на примере условных типов i2 и u2. Их нет среди числовых типов Rust, но умозрительно с ними будет проще работать. Возможно, вы обратили внимание, что максимальное значение, которое могут выразить знаковые типы, в почти 2 раза меньше максимального значения, которое могут выразить соответствующие беззнаковые типы! При этом для представления значений знаковые типы используют то же количество битов, что и соответствующие беззнаковые! Ситуация еще больше усложнится, если вспомнить, что компьютер представляет всю информацию в двоичном виде, в виде последовательности нулей и единиц, в том числе и числа. ОК, как перевести число из одной системы исчисления в другую мы знаем, но как выразить знаковость числа? \"Плюс\" или \"минус\" просто так не выразишь в двочном виде, это не числа.
Принято соглашение, что значение самого старшего бита знаковых типов указывает на знак числа этого типа: 0 — положительное число (т.е. знак необязателен и отсутствует), 1 — отрицательное число (знак обязателен и присутствует). Беззнаковые типы все биты используют для представления значения, поэтому имеют лишний бит для этого, с чем и связана способность выражать вдвое большее максимальное математическое число.
Типы i2 и u2 содержат по 2^2 = 4 значения. Выпишем их, учитывая соглашение об указании знака в старшем бите у знаковых типов:
i2:
-2 — 10 (знак обязателен, поэтому старший бит содержит 1)
-1 — 11 ^
0 — 00 (знак необязателен, поэтому старший бит содержит 0)
1 — 01 ^
u2:
0 — 00 (знаковый бит отсутствует, все биты служат для выражения значения)
1 — 01
2 — 10
3 — 11
Выпишем парами значения обоих типов, чьи двоичные представления совпадают:
0 0
1 1
2 -2
3 -1
Если проанализировать, то можно сделать заключение, что половина диапазона соответствующих друг другу знакового и беззнакового типа совпадают. Это положительная половина знакового диапазона знакового типа. Дальше начинаются чудеса. Выглядит так, словно дальнейшее соответствие приводит к тому, что отрицательная часть диапазона знакового типа \"приставляется\" после правой границы его диапазона, благодаря чему и достигается закольцованность диапазона, которая оказывается не математической абстракцией, а практическим следствием реализации представления чисел в машине! Действительно, если к двоичному представлению 1_i2 добавить единицу, то получится -2_i2 (01 + 1 = 10), то есть от правой границы происходит переход к левой, а если к двоичному представлению 3_u2 добавить единицу, то получится 0_u2 (11 + 1 = 10; на самом деле получится 100, но лишний старший бит откидывается, поскольку у нас тип ограничен 2-мя бита для представления значений).
Но постойте, остановит меня внимательный читатель. Разве при движении от 0 в отрицательную сторону двоичное представление каждого последующего числа не должно быть больше предыдущего, что не выполняется у нас, ведь соответствующее -2 10 меньше соответствующего -1 11?
Настало время раскрыть карты. Во-первых, в математике как раз чем ближе к 0, тем отрицательное число больше. Во-вторых, подобное соображение действительно справедливо, но для прямого кода. Но на большинстве популярных ныне процессорных архитектур используется дополнительный код (\"two\'s complement\", оригинальный англоязычный термин).
Приведу краткую цитату, чтобы пояснить как были получены двоичные представления для -1 и -2.
Преобразование числа из прямого кода в дополнительный осуществляется по следующему алгоритму:
* Если старший (знаковый) разряд числа, записанного в прямом коде, равен 0, то число положительное и никаких преобразований не делается;
* Если старший (знаковый) разряд числа, записанного в прямом коде, равен 1, то число отрицательное, все разряды числа, кроме знакового, инвертируются, а к результату прибавляется 1.
То есть бинарные представления положительных значений выглядят одинаково как при прямом кодировании, так и при дополнительном. Чтобы получить представления для -1, берем 01, инвертируем (т.е. вместо каждого значения битов записываем обратный: вместо 0 — 1, а вместо 1 — 0), получая 10 (так называемый \"обратный код\"), а прибавив 1, получим 11. Вуаля.
Так как я сам искал примерно минуту в черновике то место, к которому потребовалось приложить столь пространные лирические отступления, повторю его еще раз:
• C != C1, N == N1 (i32 -> u32): преобразование между двумя целыми одинакового размера является \"нулевой операцией\", NOP.
Как мы увидели, соответствующие друг другу значения знакового и беззнакового типа имеют одинаковое бинарное представление, поэтому преобразовывать их каким-либо образом друг в друга не нужно.
• C == C1, N > N1: преобразование из целого большего размера в целое меньшего размера одной категории (u32 -> u8) приведет к усечению пространства, которое используется для представления значения числа, т.е. освободится (N - N1) бит памяти.
Просто выкидываем нужное количество старших битов, и всего-то. Хотя есть один нюанс, ведь самый старший бит у знаковых типов является знаковым, и как быть с ним? Его тоже отбрасывают, НО новый самый старший бит заполняют 1.
• C == C1, N меньше N1: преобразование из целого меньшего размера в целое большего размера (i32 -> u32) приведёт к:
* zero extension, если исходное число беззнаковое целое.
* sign extension, если исходное число знаковое целое.
То есть если число положительное, то добавляем нужное количество разрядов и забиваем новые старшие биты нолями, если отрицательное — забиваем единицами.
Оказывается, это корректно и отлично работает. Если хотите, уделите время, чтобы восхититься еще раз этой великолепной абстракцией под названием \"дополнительный код\".
• Преобразование из числа с плавающей точкой к целому числу приведет к округлению первого в направлении нуля.
ПРИМЕЧАНИЕ: на текущий момент подобное округление приведёт к UB (Undefined Behavior), если округленное значение не может быть представлено конечным целым типом, включая Inf и NaN. Это баг, и будет исправлено.
• Преобразование из целого в число с плавающей точкой произведет соответствующее исходному целому число с плавающей точкой, округленное при необходимости (стратегия округления не определена).
• Преобразование из f32 в f64 совершенно и происходит без потерь.
• Преобразование из f64 в f32 произведет максимально близкое возможное значение (стратегия округления не определена).
ПРИМЕЧАНИЕ: на текущий момент подобное округление приведёт к UB (Undefined Behavior), если значение конечно, но больше или меньше, чем большее или меньшее конечное значение представимое f32. Это баг, и будет исправлено.
================================================================================
Неожиданно для меня материал получился довольно большим. Но остальное займет меньше времени. Стэй тюнед, о\'ревуар.
Примечания:
вообще-то я знаком с Rust\'ом только первый год ;
Сколько лет себя помню изучающим Rust , столько меня изводило весьма смутное понимание, что же такое \"каст\" в Rust. Я понимал, что это выглядит [...] читать описание
