Разрабатывая контейнерные смарт-контракты для Juno на Rust, я должен признать, что пока не умею писать код на этом языке программирования. На самом деле, я даже считаю себя нубом. Вот почему, когда мне приходится использовать новые шаблоны, мне иногда требуется немного времени, чтобы понять, как это сделать. Это был именно тот случай, когда я хотел передать асинхронную функцию в качестве параметра обратного вызова другой функции.
Поскольку нет лучшей документации для себя в будущем, чем ведение блога, позвольте мне поделиться решением, которое я обнаружил в ходе этого интригующего процесса.
Решение
Мой интерес к этому решению был вызван необходимостью рефакторинга моей кодовой базы и реализации шаблона, в котором существующая функция преобразовывалась бы в фабрику, при этом некоторые ее части становились динамическими, сохраняя при этом свои асинхронные характеристики.
Чтобы схематически представить эту идею в этой статье, давайте представим две разные функции: инкремент и квадратную функцию, которые принимают одни и те же параметры и возвращают один и тот же результат.
type MyParam = u64; type MyResult = u64; async fn inc( value: MyParam, ) -> MyResult { value + 1 } async fn square( value: MyParam, ) -> MyResult { value.pow(2) }
Теперь, когда функции имеют общую черту, мы можем приступить к реализации функции, которая принимает их в качестве параметров.
Чтобы иметь возможность передать функцию или замыкание в качестве параметра другой функции, нам нужен один из следующих трейтов (источник):
FnOnce
— это функции, которые можно вызвать один разFnMut
— это функции, которые можно вызывать, если у них есть&mut
доступ к своей среде.Fn
— это функции, которые можно вызывать, если у них есть только&
доступ к своей среде.
Кроме того, из-за асинхронного характера функции, которую мы хотим передать, следует указать, что она возвращает Future
. Будущее представляет собой асинхронное вычисление, полученное с использованием async
.
Наконец, хотя его можно было встроить, из соображений удобочитаемости я счел удобным использовать ограничения where
.
use std::future::Future; async fn execute<F, Fut>( f: F, value: MyParam, ) -> MyResult where F: FnOnce(MyParam)…