Browse Source

Translate ch04-03-slices.md via GitLocalize

pull/1115/head
Alexander Andreev 3 years ago committed by gitlocalize-app[bot]
parent
commit
4aa9ef6972
  1. 32
      rustbook-ru/src/ch04-03-slices.md

32
rustbook-ru/src/ch04-03-slices.md

@ -32,9 +32,9 @@ fn first_word(s: &String) -> ? @@ -32,9 +32,9 @@ fn first_word(s: &String) -> ?
{{#rustdoc_include ../listings/ch04-understanding-ownership/listing-04-07/src/main.rs:iter}}
```
Мы обсудим итераторы более подробно в [Главе 13]<!-- ignore -->. На данный момент знайте, что `iter` — это метод, который возвращает каждый элемент в коллекции, а `enumerate` оборачивает результат `iter` и вместо этого возвращает каждый элемент как часть кортежа. Первый элемент кортежа, возвращаемый из `enumerate`, является индексом, а второй элемент — ссылкой на элемент. Это немного удобнее, чем вычислять индекс самостоятельно.
Мы обсудим итераторы более подробно в [Главе 13](ch13-02-iterators.html)<!-- ignore -->. На данный момент знайте, что `iter` — это метод, который возвращает каждый элемент в коллекции, а `enumerate` оборачивает результат `iter` и вместо этого возвращает каждый элемент как часть кортежа. Первый элемент кортежа, возвращаемый из `enumerate`, является индексом, а второй элемент — ссылкой на элемент. Это немного удобнее, чем вычислять индекс самостоятельно.
Поскольку метод `enumerate` возвращает кортеж, мы можем использовать шаблоны для деструктурирования этого кортежа. Мы подробнее обсудим шаблоны в [Главе 6.]<!-- ignore -->. В цикле `for` мы указываем шаблон, имеющий `i` для индекса в кортеже и `&item` для одного байта в кортеже. Поскольку мы получаем ссылку на элемент из `.iter().enumerate()`, мы используем `&` в шаблоне.
Поскольку метод `enumerate` возвращает кортеж, мы можем использовать шаблоны для деструктурирования этого кортежа. Мы подробнее обсудим шаблоны в [Главе 6.](ch06-02-match.html#patterns-that-bind-to-values)<!-- ignore -->. В цикле `for` мы указываем шаблон, имеющий `i` для индекса в кортеже и `&item` для одного байта в кортеже. Поскольку мы получаем ссылку на элемент из `.iter().enumerate()`, мы используем `&` в шаблоне.
Внутри цикла `for` мы ищем байт, представляющий пробел, используя синтаксис байтового литерала. Если мы находим пробел, мы возвращаем позицию. В противном случае мы возвращаем длину строки с помощью `s.len()`.
@ -78,7 +78,7 @@ fn second_word(s: &String) -> (usize, usize) { @@ -78,7 +78,7 @@ fn second_word(s: &String) -> (usize, usize) {
<img alt="world containing a pointer to the 6th byte of String s and a length 5" src="img/trpl04-06.svg" class="">
<span class="caption">Рисунок 4-6: Фрагмент строки, относящийся к части <code>String</code></span>
<span class="caption">Figure 4-6: String slice referring to part of a <code>String</code></span>
С синтаксисом Rust `..`, если вы хотите начать с индекса 0, вы можете отбросить значение перед двумя точками. Другими словами, они равны:
@ -111,9 +111,7 @@ let slice = &s[0..len]; @@ -111,9 +111,7 @@ let slice = &s[0..len];
let slice = &s[..];
```
> Внимание: Индексы среза строк должны соответствовать границам UTF-8 символов. Если вы попытаетесь получить срез нарушая границы символа в котором больше одного байта, то вы получите ошибку времени исполнения. В рамках этой главы мы будем предполагать только ASCII кодировку. Более детальное обсуждение UTF-8 находится в секции ["Сохранение текста с кодировкой UTF-8 в строках"]
> <!-- ignore -->
> Главы 8.
> Внимание: Индексы среза строк должны соответствовать границам UTF-8 символов. Если вы попытаетесь получить срез нарушая границы символа в котором больше одного байта, то вы получите ошибку времени исполнения. В рамках этой главы мы будем предполагать только ASCII кодировку. Более детальное обсуждение UTF-8 находится в секции ["Сохранение текста с кодировкой UTF-8 в строках"](ch08-02-strings.html#storing-utf-8-encoded-text-with-strings)
Давайте используем полученную информацию и перепишем метод `first_word` так, чтобы он возвращал срез. Для обозначения типа "срез строки" существует запись `&str`:
@ -125,7 +123,7 @@ let slice = &s[..]; @@ -125,7 +123,7 @@ let slice = &s[..];
Мы получаем индекс конца слова так же, как в листинге 4.7, ища первое вхождение пробела. Когда мы находим пробел, мы возвращаем фрагмент строки, используя начало строки и индекс пробела в качестве начального и конечного индексов.
Теперь, вызвав метод first_word, мы получим одно единственное значение, которое привязано к нижележащим данным. Значение, которое составлено из ссылки на начальную точку среза и количества элементов в срезе.
Теперь, когда мы вызываем `first_word`, мы возвращаем одно значение, привязанное к базовым данным. Значение состоит из ссылки на начальную точку среза и количества элементов в срезе.
Аналогичным образом можно переписать и второй метод `second_word`:
@ -133,7 +131,7 @@ let slice = &s[..]; @@ -133,7 +131,7 @@ let slice = &s[..];
fn second_word(s: &String) -> &str {
```
Теперь есть простое API, работу которого гораздо сложнее испортить, потому что компилятор обеспечивает нам то, что ссылки на `String` останутся действительными. Помните ошибку в программе листинга 4-8, когда мы получили индекс конца первого слова, но затем очистили строку, так что она стала недействительной? Тот код был логически некорректным, хотя не показывал никаких ошибок. Проблемы возникли бы позже, если бы мы попытались использовать индекс первого слова для пустой строки. Срезы делают невозможной данную ошибку и позволяют понять о наличии проблемы гораздо раньше. Так, использование версии метода `first_word` со срезом вернёт ошибку компиляции:
Теперь у нас есть простой API, который гораздо сложнее испортить, потому что компилятор гарантирует, что ссылки в `String` останутся действительными. Помните ошибку в программе в листинге 4-8, когда мы получили индекс до конца первого слова, но затем очистили строку, так что наш индекс стал недействительным? Этот код был логически неправильным, но не показывал немедленных ошибок. Проблемы проявятся позже, если мы попытаемся использовать индекс первого слова с пустой строкой. Срезы делают эту ошибку невозможной и сообщают нам о проблеме с нашим кодом гораздо раньше. Использование слайсовой версии `first_word` вызовет ошибку времени компиляции:
<span class="filename">Файл: src/main.rs</span>
@ -161,17 +159,17 @@ fn second_word(s: &String) -> &str { @@ -161,17 +159,17 @@ fn second_word(s: &String) -> &str {
let s = "Hello, world!";
```
Тип `s` здесь является `&str` срезом, указывающим на конкретное место в бинарном файле программы. Это также объясняет, почему строковый литерал является неизменяемым, потому что тип `&str` это неизменяемая ссылка.
Тип `s` здесь `&str`: это срез, указывающий на эту конкретную точку двоичного файла. Вот почему строковые литералы неизменяемы; `&str` неизменяемая ссылка.
#### Строковые срезы как параметры
Знание о том, что можно брать срезы строковых литералов и `String` строк приводит к ещё одному улучшению метода `first_word` улучшению его сигнатуры:
Знание того, что вы можете брать срезы литералов и `String` значений, приводит нас к еще одному улучшению `first_word`, и это его сигнатура:
```rust,ignore
fn first_word(s: &String) -> &str {
```
Более опытные разработчики Rust написали бы сигнатуру из листинга 4-9, потому что она позволяет использовать одну функцию для значений обоих типов `&String` и `&str`.
Более опытный пользователь Rustacean вместо этого написал бы сигнатуру, показанную в листинге 4.9, потому что это позволяет нам использовать одну и ту же функцию как для значений `&String`, так и для значений `&str`.
```rust,ignore
{{#rustdoc_include ../listings/ch04-understanding-ownership/listing-04-09/src/main.rs:here}}
@ -179,7 +177,7 @@ fn first_word(s: &String) -> &str { @@ -179,7 +177,7 @@ fn first_word(s: &String) -> &str {
<span class="caption">Листинг 4-9: Улучшение функции <code>first_word</code> используя тип строкового среза для параметра <code>s</code></span>
Если у нас есть фрагмент строки, мы можем передать его напрямую. Если у нас есть `String`, мы можем передать часть `String` или ссылку на `String`. Эта гибкость использует преимущества *приведения deref*, функции, которую мы рассмотрим в [разделе «Неявное приведение Deref с функциями и методами».]<!-- ignore --> раздел главы 15.
Если у нас есть фрагмент строки, мы можем передать его напрямую. Если у нас есть `String`, мы можем передать часть `String` или ссылку на `String`. Эта гибкость использует преимущества *приведения deref*, функции, которую мы рассмотрим в [разделе «Неявное приведение Deref с функциями и методами».](ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods)<!-- ignore --> раздел главы 15.
Определение функции для получения фрагмента строки вместо ссылки на `String` делает наш API более общим и полезным без потери какой-либо функциональности:
@ -207,16 +205,10 @@ let slice = &a[1..3]; @@ -207,16 +205,10 @@ let slice = &a[1..3];
assert_eq!(slice, &[2, 3]);
```
Данный срез имеет тип `&[i32]`. Он работает таким же образом, как и строковый срез, сохраняя ссылку на первый элемент и длину. Вы будете использовать данную разновидность среза для всех видов коллекций. Мы обсудим коллекции детально, когда будем говорить про векторы в Главе 8.
Этот срез имеет тип `&[i32]`. Он работает так же, как и срезы строк, сохраняя ссылку на первый элемент и его длину. Вы будете использовать этот вид фрагмента для всех видов других коллекций. Мы подробно обсудим эти коллекции, когда будем говорить о векторах в главе 8.
## Итоги
Концепции владения, заимствования и срезов обеспечивают защиту использования памяти в Rust. Rust даёт вам возможность контролировать использование памяти тем же способом, как другие языки системного программирования, но дополнительно предоставляет возможность автоматической очистки данных, когда их владелец покидает область видимости функции. Это означает, что не нужно писать и отлаживать дополнительный код, чтобы добиться такого контроль.
Концепции владения, заимствования и срезов обеспечивают безопасность памяти в программах на Rust во время компиляции. Язык Rust дает вам контроль над использованием памяти так же, как и другие языки системного программирования, но то, что владелец данных автоматически очищает эти данные, когда владелец выходит за рамки, означает, что вам не нужно писать и отлаживать дополнительный код, чтобы получить этот контроль.
Владение влияет на множество других частей и концепций языка Rust. Мы будем говорить об этих концепциях на протяжении оставшихся частей книги. Давайте перейдём к Главе 5 и рассмотрим группировку частей данных в структуры `struct`.
[Главе 13]: ch13-02-iterators.html
[Главе 6.]: ch06-02-match.html#patterns-that-bind-to-values
["Сохранение текста с кодировкой UTF-8 в строках"]: ch08-02-strings.html#storing-utf-8-encoded-text-with-strings
[разделе «Неявное приведение Deref с функциями и методами».]: ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods
Loading…
Cancel
Save