Shanraq.org Shanraq.org
Методы: действия рядом с Task
IT

Rust: с нуля до своего органайзера Урок 28 из 35

Методы: действия рядом с Task

Урок 28. Создать задачу, прочитать её состояние и завершить её через методы.

Текст переведён с помощью ИИ.

Предварительно: уроки 14, 20, 21 и 27. Если разница между & и &mut забылась, повторите урок 21.

Образ и опорная карта

У карточки задачи есть не только заполненные графы, но и действия: прочитать состояние, отметить выполнение. Метод — функция, связанная с типом и вызываемая через значение этого типа. Блок impl Task { ... } собирает такие действия рядом с описанием Task; impl означает «реализация». Образ ограничен: карточка сама ничего не делает — код метода явно выполняется при вызове.

struct Taskimpl TaskTask::new(...)task.is_done()task.finish(). Перескажите карту. Функция new внутри impl без параметра self связана с типом и вызывается как Task::new(...); :: показывает путь от типа к функции, как в String::from(...). Это связанная функция, а не метод экземпляра. Метод имеет первый параметр self: &self берёт задачу для чтения, &mut self — для изменения. При вызове task.is_done() или task.finish() Rust передаёт task как этот первый параметр автоматически.

Читаем и меняем задачу

Сохраните прежний src/main.rs проекта organizer, замените его целиком и запустите cargo run рядом с Cargo.toml. Других файлов и зависимостей нет. Сначала предскажите результат.

new принимает название и минуты, создаёт Task с done: false и возвращает его. В Task { title, minutes, done: false } два имени без : — сокращённая запись полей: это title: title, minutes: minutes, потому что имена параметров совпадают с именами полей. Здесь переданы известные нам подходящие значения; функция пока не проверяет пользовательский ввод. is_done возвращает копируемый bool и не меняет задачу. finish меняет поле, поэтому требует &mut self и изменяемой переменной task.

struct Task {
    title: String,
    minutes: u32,
    done: bool,
}

impl Task {
    fn new(title: String, minutes: u32) -> Task {
        Task {
            title,
            minutes,
            done: false,
        }
    }

    fn is_done(&self) -> bool {
        self.done
    }

    fn finish(&mut self) {
        self.done = true;
    }
}

fn main() {
    let mut task = Task::new(String::from("Чтение"), 20);
    println!(
        "{}: {} мин, готово {}",
        task.title,
        task.minutes,
        task.is_done()
    );
    task.finish();
    println!("После: {}", task.is_done());
}
Чтение: 20 мин, готово false
После: true

title передаёт владение строкой в новый экземпляр. У finish нет стрелки результата; значит, он возвращает () из урока 14. Заимствование через &mut self заканчивается после вызова, и is_done снова может читать задачу.

Когда &mut self нельзя взять

Если переменная не объявлена mut, метод изменения не может получить изменяемую ссылку. Этот отдельный пример намеренно не компилируется с E0596:

struct Task { done: bool }
impl Task {
    fn finish(&mut self) { self.done = true; }
}
fn main() {
    let task = Task { done: false };
    task.finish();
}

Добавление mut к task разрешит вызов. Но методы не отменяют правил владения: &self не меняет поля, а &mut self требует исключительного доступа на время вызова. new здесь не запрещает 0 минут. Полную проверку значений и сообщение об ошибке добавим, когда освоим Result.

Проверьте себя

  1. Зачем new вызывается через Task::, а finish через task.?
  2. Какой метод требует изменяемой переменной?
  3. Почему после finish() можно вызвать is_done()?

Проверьте: new не принимает экземпляр; finish берёт &mut self; его временное заимствование закончилось. Проговорите цепочку из опорной карты без страницы.

Задание

Обязательное. Объявите Task { title: String, done: bool }. В impl Task сделайте new(title: String) -> Task, метод is_done(&self) -> bool и finish(&mut self). Создайте изменяемую задачу Прогулка, выведите Прогулка: false, завершите её и выведите Прогулка: true. Оба значения состояния получите через метод.

Изменение. Уберите mut перед переменной, прочитайте ошибку, затем верните mut.

Подсказка

new создаёт Task { title, done: false }. finish записывает self.done = true;. Вызовите task.is_done() до и после task.finish().

Эталон после попытки

struct Task {
    title: String,
    done: bool,
}

impl Task {
    fn new(title: String) -> Task {
        Task { title, done: false }
    }

    fn is_done(&self) -> bool {
        self.done
    }

    fn finish(&mut self) {
        self.done = true;
    }
}

fn main() {
    let mut task = Task::new(String::from("Прогулка"));
    println!("{}: {}", task.title, task.is_done());
    task.finish();
    println!("{}: {}", task.title, task.is_done());
}
Прогулка: false
Прогулка: true

Данные и относящиеся к ним действия находятся рядом. Официальный разбор методов.

Предыдущий урок · Оглавление · Следующий урок

Если вы нашли ошибку или опечатку в тексте статьи, то сообщите нам об этом

Комментарии (0)

Пока нет комментариев. Будьте первым.