Comments

Отличная статья, читал на одном дыхании. Пишите ещё! Единственное что не понял это функция toSoldier. Функция принимает на вход некий self, а в маппере передаёте ей школьника. Как компилятор вывел из него имя?

Функция находится в блоке impl Scholar. Соответственно, она в качестве первого аргумента может принимать:


  • self, т.е. self: Scholar,
  • &self, т.е. self: &Scholar,
  • &mut self, т.е. self: &mut Scholar,
  • и, если не ошибаюсь, аналогично Pin<Box<self>> и Pin<&mut self>, но это уже экзотика;
  • ну, или ничего из перечисленного — тогда это будет не метод, а ассоциированная функция (статический метод, если угодно), которая вызывается на типе, а не на объекте.

Не надо так (это означает, что в дизайне структур данных что-то пошло не так, единичные кейсы исключительные кейсы, когда это нужно):


Pin<Box<self>>

Да и Pin<T> — это экзотика из-за ее документации. Редкий новичок или поверхностный погруженец позволит съесть свой мозг чайной ложечкой.

Этот код уже валидный, потому что владелец по прежнему один (сначала first, потом third). При этом изменение владельца никак не повлияло на second, ссылка будет продолжать указывать куда указывала.

Нет, нет, нет. Не надо так. Простой контрпример:


struct X; //объявляем структуру

fn test_borrow_checker () -> X {
    let first = X; // создаём экземпляр
    let second: &X = &first; // не меняем владельца, а берём ссылку на значение
    let third = first; // забираем владение X, всё вроде бы окей
    let fourth = second; // упс, first исчез, ссылка невалидна!

    return third;
}

В Вашем примере всё работает не потому, что заимствование в second не затронуто перемещением, а потому, что оно попросту не используется, и borrow-checker — как Вы позже заметили применительно к уникальным (изменяемым) заимствованиям — достаточно умный, чтобы это заметить.

Да, вы правы, и параграф после этого кода соответственно тоже не точный. Постараюсь исправить сегодня. Спасибо)
Про Box и Arc — они довольно простые, по идее могу. А вот с Pin самому надо доразобраться, так что это хороший повод написать.
По-этому просто iter() и работа с двойной ссылкой

Не обязательно загромождать код оператором разыменования, тк в rust есть deref coercion и компилятор может автоматически разыменовывать ссылки (примерно как в c++):


fn good_idea() {
    let scholars: Vec<Scholar> = Vec::new();
    let girls_c = scholars.iter().filter(|s| s.sex == Sex::Female).count();
    let boys_c = scholars.iter().filter(|s| s.sex == Sex::Male).count();
}

Аналогично в других кусках кода.

О! А это объясняет почему такая «кривлять» как двойное разыменованием на ровном месте есть в языке. Программист его все равно не заметит.


Правда я так и не понял зачем нужна ссылка на ссылку… они же немутабельные.

Тут скорее не "зачем", а "почему". Следите за руками:


  • Нужен итератор, который не требует отдавать ему целиком вектор. Для этого нужно, чтобы он получал не элементы вектора, а только ссылки на них.
  • Нужен адаптер для итератора, который не требует отдавать ему элементы исходного итератора (они ещё пригодятся дальше в цепочке). Для этого нужно, чтобы он получал не элементы итератора, а ссылки на них.

Оба этих требования не зависят ни от типа элементов вектора, ни от типа элементов в итераторе — даже несмотря на то, что в некоторых случаях можно просто копировать исходные элементы (и это реально будет делаться, если в цепочку вставить copied()), сигнатуры методов Vec::iter() и Iterator::filter() остаются одни и те же. Отсюда и двойная ссылка — потому что есть две независимые причины эти самые ссылки навесить.

Можно просто писать ссылку в аргументе лямбды. Так: |&s| ..., Тогда внутри лямбды уже можно точно без разименовывания.

Спасибо! Очень просто и интересно написано. Продолжайте в том же духе!
Если вы понимаете английский, то рекомендую вот это видео. По идее после его просмотра и некоторого количества самостоятельных экспериментов вопросов остаться не должно.
Вообще, имхо, последняя версия rustbook'а довольно неплохо это объясняет. Лучше первой. Правда в русском переводе есть настолько синтетический и неестественный текст, что иногда вникать тяжело, но в принципе понятно.
Если интересно, то могу продолжить. Варианты тем:
Голосую за веб-сервис. API самое очевидное — Conduit. В идеале без макросов ).
И там и там все на макросах. Это слишком легко написать, но ИМХО сложно объяснить/разобраться что происходит «под капотом».
Only those users with full accounts are able to leave comments. Log in, please.