Допустим, я хочу хранить данные в SQLite. Также я не хочу дёргать SQLite напрямую из main, а хочу сделать задаче-специфичную обёртку, предоставляющую методы вида «положить яблоки», «запросить количество груш», а не SQL-запросы. Потому что мне в целом не принципиально, что там под капотом и с тем же успехом вместо БД я мог бы использовать текстовый файл (просто БД будет лучше себя вести на большом объёме данных не влезающем в ОЗУ).
Ну что ж, берём SQLite:
let connection = sqlite::open("db.sqlite").unwrap();
let mut statement = connection.prepare("SELECT COUNT(*) FROM pears").unwrap();
А теперь мы хотим положить connection и statement в одну структуру FruitStorage, у которой будет метод count_pears(). И не можем. Потому что statement требует лайфтайм connection. И не позволяет их Rust класть в одну структуру.
Можно, конечно, сделать две структуры. FruitStorage содержащий connection с методом get_fruit_counter, возвращающим FruitCounter, который уже содержит в себе statement и имеет метод count_pears(), при этом имеет лайфтайм FruitStorage. Но это явное очень сильное протекание абстракции. У нас потом могут быть ещё более высокоуровневые абстракции, а деталь реализации «для работы с SQLite нужно два отдельных объекта - соединение и подготовленный запрос» будет и дальше нас приследовать.
Как такое решается?