В каких случаях предпочтительны API, которые не заимствуют? - PullRequest
0 голосов
/ 16 декабря 2018

Руст имеет понятия собственности и заимствования.Если функция не заимствует свой параметр в качестве ссылки, аргументы этой функции перемещаются и будут освобождены после выхода из области видимости.

Возьмите эту функцию:

fn build_user(email: String, username: String) -> User {
    User {
        email: email,
        username: username,
    }
}

Эту функцию можно вызвать следующим образом:

let email = String::from("foo@example.com");
let username = String::from("username");

let user = build_user(email, username);

Поскольку email и username были перемещены, их нельзя использовать после вызова build_user.

Это может бытьисправлено, заставляя API использовать заимствованные ссылки.

Имея это в виду, какие сценарии всегда предпочтительнее не использовать заимствования при разработке API?

1 Ответ

0 голосов
/ 16 декабря 2018

Этот список может быть не исчерпывающим, но во многих случаях целесообразно не брать аргументы.

1.Эффективность с небольшими Copy типами

Если тип маленький и реализует Copy, обычно более эффективно копировать его, чем передавать указатели.Ссылки означают косвенность - помимо необходимости выполнять два шага для получения данных, значения за указателями с меньшей вероятностью будут компактно храниться в памяти и, следовательно, медленнее копировать в кэши ЦП, например, если вы выполняете итерации по ним.

2.Передача права собственности

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

3.Цепочка методов

Если набор методов все потребляют self и возвращают Self, вы можете удобно объединить их в цепочку, не требуя промежуточных локальных переменных.Вы часто будете видеть этот подход, используемый для реализации сборщиков.Вот пример, взятый из документации derive_builder crate :

let ch = ChannelBuilder::default()
    .special_info(42u8)
    .token(19124)
    .build()
    .unwrap();

4.Статическое применение инвариантов

Иногда требуется, чтобы значение использовалось функцией для гарантии того, что оно не может быть использовано снова, как способ применения допущений на уровне типа.Например, в futures ящике метод Future::wait потребляет self:

fn wait(self) -> Result<Self::Item, Self::Error> 
where
    Self: Sized,

Эта подпись специально разработана для предотвращения повторного вызова wait.Реализация не должна проверять во время выполнения, чтобы увидеть, находится ли будущее уже в состоянии ожидания - компилятор просто не допустит такой ситуации.

Она также обеспечивает защиту от ошибок при использовании построенных по методам компоновщиков,Конструкция статически не позволяет вам делать вещи не по порядку - вы не можете случайно установить поле на построителе после того, как объект создан, потому что построитель используется его методом build.

5.Чтобы сделать клонирование явным для вызывающих абонентов

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...