Радует, что Rust — на передовой линии, в плане поддержки Wasm. Хороший современный системный язык, который все больше становится языком общего назначения. Может быть лучшие дни популярности FireFox уже и прошли, но мне нравится, как Mozilla борется за "место под солнцем", вкладываясь в такие фундаментальные технологии, как Wasm и Rust.
Я к тому, что проблема в принципе решаема и некоторые решения уже есть. Их не так много и они не так хороши, как хотелось бы, потому что проблема эта еще не стала массовой.
Поэтому существуют децентрализованные сети. В вашей схеме Чей-то сервис — им может быть и децентрализованный сервис, и машина самого пользователя, в том числе.
Ну и что с того? У вас же монтироваться они будут в одном месте — переходите к указанной функции-обработчику и все. Наоборот, удобно, что та часть запроса, которая должна соответствовать сигнатуре обработчика, указывается рядом с этой сигнатурой. Более того, так как она задается в процедурном макросе, мы можем проверять во время компиляции это соответствие.
Ну сейчас устаканивается Rust 2018, поэтому в основном завершается стабилизация уже разработанного ранее. Константы в обобщенных типах еще требуют серьезной разработки и широкого тестирования, так что в нынешнем году мы их точно не увидим в стабильном Rust.
В Cell-ах и трехэтажных шаблонах все же лучше сразу разобраться, чтобы понимать, как реализовывать некоторые, привычные по другим языкам программирования вещи в Rust.
Допустим у вас есть некий объект и вы хотите хранить ссылки на него в нескольких местах одновременно. Но тут возникает сразу две проблемы:
Объект должен быть доступен из разных мест по ссылке, и удален только тогда, когда на него нет ссылок. Если есть по крайней мере одна ссылка, то объект должен жить.
Правила Rust позволяют иметь больше одной ссылки только на неизменяемый объект. Ссылка на изменяемый объект может быть только одна, без каких либо других ссылок на этот объект.
Первая проблема решается подсчетом ссылок (reference counting) и в других популярных прикладных ЯП она обычно скрыта от пользователя за реализацией. То есть любая "ссылка" на объект в таких ЯП всегда есть умный указатель со счетчиком ссылок. В Rust же такого типа ссылку нужно создавать вручную, если она вам нужна. Для этого используются типы Rc и Arc. Кроме того, нужно как-то решать вопрос образования циклических ссылок (Weak).
Вторая проблема решается введением совместно используемых изменяемых контейнеров — это типы Cell, RefCell, Mutex, RwLock.
Если вам не обязательно хранить ссылку на родителя в дочернем элементе, то реализация будет тривиальна. В противном случае вам придется:
Использовать Rc, RefCell и прочие Weak; или
Использовать сырые указатели и управлять освобождением памяти вручную; или
Хранить узлы во внешнем контейнере и ссылаться на них по индексу; или
Использовать готовые библиотеки, которые скрывают всю кухню за своим API.
Вообще, для лучшего понимания, рекомендую изучить реализацию rust-forest. Там представлено несколько подходов и они довольно неплохо прокомментированы.
Несмотря на то, что Rust позиционируется как системный язык программирования, он также является языком программирования общего назначения. Что плохого в том, что как системный ЯП Rust имеет развитую систему типов и довольно высокоуровневые абстракции с нулевой стоимостью, а как прикладной ЯП — высокую производительность?
Из того, что мы "толком не знаем" не следует, что обработка ошибок не будет осуществлена также "здесь и сейчас", выражаясь вашей терминологией. Объявляется обработчик отдельно, но "определяется" он точно также в месте возникновения ошибки: просто связь устанавливается не по имени, а по порядку следования. Только в этом отличие.
Так что вы изначально хотели получить от Rust'а? Возможность устанавливать обработчик положением в потоке кода? Так нельзя (без макросов). Я ваш исходный комментарий понял так, что вас интересует возможность определить обработку ошибки не в том же месте, где она возникает. Но вы как-то странно понимаете, что значит "определить обработку". В итоге у вас получается, что action().map_err(handle) — определяет обработчик handle в месте возникновения ошибки, а check action() + положение этой строки в потоке кода — не определяет обработчик ошибки в этом месте ее возникновения.
Радует, что Rust — на передовой линии, в плане поддержки Wasm. Хороший современный системный язык, который все больше становится языком общего назначения. Может быть лучшие дни популярности FireFox уже и прошли, но мне нравится, как Mozilla борется за "место под солнцем", вкладываясь в такие фундаментальные технологии, как Wasm и Rust.
На Хабре, кстати, есть ее перевод: WebAssembly — это возвращение апплетов Java и Flash?
Я к тому, что проблема в принципе решаема и некоторые решения уже есть. Их не так много и они не так хороши, как хотелось бы, потому что проблема эта еще не стала массовой.
Поэтому существуют децентрализованные сети. В вашей схеме Чей-то сервис — им может быть и децентрализованный сервис, и машина самого пользователя, в том числе.
Обещанный блог-пост таки вышел, слегка с опозданием: Help test Rust 2018
Ну и что с того? У вас же монтироваться они будут в одном месте — переходите к указанной функции-обработчику и все. Наоборот, удобно, что та часть запроса, которая должна соответствовать сигнатуре обработчика, указывается рядом с этой сигнатурой. Более того, так как она задается в процедурном макросе, мы можем проверять во время компиляции это соответствие.
В unsafe Rust первая проблема решается:
Ну сейчас устаканивается Rust 2018, поэтому в основном завершается стабилизация уже разработанного ранее. Константы в обобщенных типах еще требуют серьезной разработки и широкого тестирования, так что в нынешнем году мы их точно не увидим в стабильном Rust.
В Cell-ах и трехэтажных шаблонах все же лучше сразу разобраться, чтобы понимать, как реализовывать некоторые, привычные по другим языкам программирования вещи в Rust.
Допустим у вас есть некий объект и вы хотите хранить ссылки на него в нескольких местах одновременно. Но тут возникает сразу две проблемы:
Первая проблема решается подсчетом ссылок (reference counting) и в других популярных прикладных ЯП она обычно скрыта от пользователя за реализацией. То есть любая "ссылка" на объект в таких ЯП всегда есть умный указатель со счетчиком ссылок. В Rust же такого типа ссылку нужно создавать вручную, если она вам нужна. Для этого используются типы
Rc
иArc
. Кроме того, нужно как-то решать вопрос образования циклических ссылок (Weak
).Вторая проблема решается введением совместно используемых изменяемых контейнеров — это типы
Cell
,RefCell
,Mutex
,RwLock
.Я рекомендую прочитать вот эту страницу официальной документации и разобрать приведенный там пример с гаджетами для того, чтобы понять, для чего и как использовать
Rc
,RefCell
иWeak
вместе. Также рекомендую ознакомиться с документацией по cell.Если вам не обязательно хранить ссылку на родителя в дочернем элементе, то реализация будет тривиальна. В противном случае вам придется:
Rc
,RefCell
и прочиеWeak
; илиВообще, для лучшего понимания, рекомендую изучить реализацию
rust-forest
. Там представлено несколько подходов и они довольно неплохо прокомментированы.Ну вот посмотрите, как это делается в Rocket:
То есть атрибуту на откуп отдается указание метода и параметров запроса, а к корневой части пути разные обработчики монтируются в одном месте.
Хотя у меня нормально отображается и в узкой консоли:
Вообще-то Rust не избавляет от утечек памяти.
Если речь про todomvc, то вот:
Из того, что мы "толком не знаем" не следует, что обработка ошибок не будет осуществлена также "здесь и сейчас", выражаясь вашей терминологией. Объявляется обработчик отдельно, но "определяется" он точно также в месте возникновения ошибки: просто связь устанавливается не по имени, а по порядку следования. Только в этом отличие.
В Rust'е, слава богу, такого поведения нет.
Так что вы изначально хотели получить от Rust'а? Возможность устанавливать обработчик положением в потоке кода? Так нельзя (без макросов). Я ваш исходный комментарий понял так, что вас интересует возможность определить обработку ошибки не в том же месте, где она возникает. Но вы как-то странно понимаете, что значит "определить обработку". В итоге у вас получается, что
action().map_err(handle)
— определяет обработчикhandle
в месте возникновения ошибки, аcheck action()
+ положение этой строки в потоке кода — не определяет обработчик ошибки в этом месте ее возникновения.