Каково эмпирическое правило при работе с передаваемыми аргументами в Rust? - PullRequest
0 голосов
/ 24 января 2019

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

Не могли бы вы предоставить какое-нибудь простое правило о передаче аргумента как T против &T, когда T является объектом / строкой? Например, в C ++ есть 3 варианта:

  • T - скопировать значение, не может изменить текущее значение
  • &T - не создавать копию, может изменить текущее значение
  • const &T - не создавать копию, не может изменить текущее значение

Например, стоит ли проходить мимо T, если я хочу освободить T после того, как он выходит из области видимости в моей функции child (функция, которую я передаю T) ; и используйте &T, если я хочу использовать свою дочернюю функцию в режиме только для чтения, а затем продолжать использовать ее в моей текущей ( parent ) функции.

Спасибо!

1 Ответ

0 голосов
/ 24 января 2019

Это правила, которые я лично использую (по порядку).

  1. Передача по значению (T), если у параметра есть универсальный тип и признак (и), которые этотвсе реализации универсального типа берут &self или &mut self , но есть общее impl для &T или &mut T (соответственно) для всех типов T, которые реализуют эту черту (или этичерты).Например, в std::io::Write все методы принимают &mut self, но в стандартной библиотеке предусмотрен общий импл impl<'a, W: Write + ?Sized> Write for &'a mut W.Это означает, что, хотя вы принимаете T (где T: Write) по значению, можно передать &mut T, поскольку &mut T также реализует Write.

  2. Передачазначение (T), если вы должны стать владельцем значения (например, потому что вы передаете его другой функции / методу, который принимает его по значению, или потому что альтернативы потребуют потенциально дорогих клонов).

  3. Передайте по изменяемой ссылке (&mut T), если вам нужно видоизменить объект (вызывая другие функции / методы, которые принимают объект по изменяемой ссылке, или просто перезаписывая его, и вы хотите, чтобы вызывающая сторона увидела новоезначение), но не нужно вступать во владение им.

  4. Передача по значению (T), если тип Copy и мал (мой критерий для малого size_of::<T>() <= size_of::<usize>() * 2, но у других людей могут быть немного другие критерии).Примитивные целочисленные типы и типы с плавающей точкой являются примерами таких типов.Передача значений этих типов по ссылке создаст ненужную косвенность в памяти, поэтому вызывающий должен будет выполнить дополнительную машинную инструкцию, чтобы прочитать ее.Когда size_of::<T>() <= size_of::<usize>(), вы обычно ничего не сохраняете, передавая значение по ссылке, потому что T и &T обычно передаются в одном регистре (если у функции достаточно мало параметров).

  5. Передача по общей ссылке (&T) в противном случае.

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

Например, является ли этохорошая идея пройти мимо T, если я хочу освободить T после того, как он выходит из области видимости в моей дочерней функции (функция, которую я передаю T)

Вы былучше иметь вескую причину для этого!Если вы когда-нибудь решите, что вам действительно нужно использовать T позже в вызывающей программе, вам придется изменить подпись вызывающей стороны и обновить все сайты вызовов (потому что в отличие от C ++, где переход от T до const T&в основном прозрачный, переход от T к &T в Rust отсутствует: вы должны добавить & перед аргументом во всех сайтах вызовов).

Я рекомендую использовать Clippy если вы еще не используете его. В Clippy есть сообщение, которое может уведомить вас, если вы напишите функцию, которая принимает аргумент по значению, но функция не должна вступать во владение ею (по умолчанию это предупреждение используется, но больше не используется.?, поэтому вы должны включить его вручную с помощью #[warn(clippy::needless_pass_by_value)]).

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