LINUX.ORG.RU

Глупые вопросы начинающего

 , ,


0

2

Доброго здоровьица, как завещал нам товарищ Малахов++(кстати чем то похож на Бьярне). Ой, чего то я отвлекся. А вопрос у меня следующий:

Есть у меня значит что то типа того:

pub struct TextEditor {
    text: String
}

impl TextEditor {
    pub fn new() -> TextEditor {
        TextEditor{text: String::new()}
    }
 
    pub fn add_char(&mut self, ch : char) {
        self.text.push(ch);
    }
}
 
fn main() {
    let mut editor = TextEditor::new();
 
    editor.add_char('a');
    editor.add_char('b');
    editor.add_char('c');
}


Почему сделано так, что нужно обязательно передавать self? Почему нельзя было сделать как в том же C++ - обращаться через this? Ну ладно, если нравится self, то все же, почему нельзя было неявным образом передавать этот self, чтобы постоянно не приходилось его передавать во все методы, где нужно обращаться к текущему объекту? Заранее спасибо за объяснение.


Последнее исправление: paret (всего исправлений: 1)

почему нельзя было неявным образом передавать этот self

Как тогда выражать разницу между self, &self и &mut self?

ovk48 ★★★
()
Ответ на: комментарий от ovk48

Как тогда выражать разницу между self, &self и &mut self?

+ тогда нужно будет придумать способ, как отличать обычные методы от «статических».

theNamelessOne ★★★★★
()
Ответ на: комментарий от ovk48

Ну вот теперь понятнее стало немного.

paret
() автор топика

Потому, что:
1. Ты можешь писать не только editor.add_char('a'), но и TextEditor::add_char(&mut editor, 'a').
2. Разница между self, &self и &mut self выражается явно.

quantum-troll ★★★★★
()
Ответ на: комментарий от quantum-troll

Но если я уже выше создал экземпляр let mut editor = TextEditor::new(), зачем мне писать TextEditor::add_char(&mut editor, 'a')? Так ведь «долго, дорого, НЕохуенно». Или это статичный метод? Тогда могу ли я сделать так TextEditor::add_char(&mut TextEditor::new(), 'a')? Хотя смысла не вижу в этом. Лол.

paret
() автор топика
Ответ на: комментарий от paret

Но если я уже выше создал экземпляр let mut editor = TextEditor::new(), зачем мне писать TextEditor::add_char(&mut editor, 'a')?

В данном случае незачем, но это позволяет передавать метод как аргумент для HOF:

struct Foo;

impl Foo {
  fn foo(&self) {
    println!("foo");
  }
}

fn run<X>(x: &X, action: fn(&X) -> ()) {
  action(x);
}

fn main() {
  let foo = Foo;
  run(&foo, Foo::foo);
}

Ещё возможна ситуация, когда тип реализует два трейта с одинаковыми именами функций:

struct Foo;

trait Bar {
  fn honk(&self);
}

trait Baz {
  fn honk(&self);
}

impl Bar for Foo {
  fn honk(&self) {
    println!("Bar");
  }
}

impl Baz for Foo {
  fn honk(&self) {
    println!("Baz");
  }
}

fn main() {
  let foo = Foo;
  // foo.honk(); — error: multiple applicable items in scope
  Bar::honk(&foo);
  Baz::honk(&foo);
}
theNamelessOne ★★★★★
()
Ответ на: комментарий от paret

Ну во-первых, консистентность. Раз можно написать TextEditor::new(), то должна и быть возможность написать TextEditor::add_char(&mut editor, 'a').
Во-вторых, это работает и для типажей, что бывает полезно.

quantum-troll ★★★★★
()
Ответ на: комментарий от theNamelessOne

ситуация, когда тип реализует два трейта с одинаковыми именами функций

Довольно-таки очевидный антипаттерн, впрочем.

quantum-troll ★★★★★
()
Ответ на: комментарий от quantum-troll

Довольно-таки очевидный антипаттерн, впрочем.

Если оба трейта пишет один и тот же человек (в пределах одной и той же библиотеки) — бесспорно.

theNamelessOne ★★★★★
()
Ответ на: комментарий от theNamelessOne

Насколько я понимаю, трейты(они же поведения) это замена наследования? То есть имеется некий интерфейс(трейт), который в принципе каждый может реализовать по-разному? И еще один вопрос: трейты это и есть типажи? просто я только начал изучать, поэтому жуткая путаница возникает. Спасибо.

paret
() автор топика
Ответ на: комментарий от quantum-troll

Подскажи плиз еще кое-что. Это скорее всего не по теме, но касается Rust. Пытаюсь понять lifetime-ы. Они задают время жизни ссылки? Допустим есть у меня 'a и 'b. Как Определить какое время жизни дольше? А в идеале очень поможешь, если «на пальцах» объяснишь для чего они и когда применяются. Насколько я понял, время жизни лучше продумать на этапе проектирования? То есть нужно хорошо продумать что и как будет, чтоб расставить приоритеты эти? Спасибо.

paret
() автор топика
Ответ на: комментарий от paret

Пытаюсь понять lifetime-ы. Они задают время жизни ссылки?

Они задают требования, которые код (разработчик кода) предъявляет к временам жизни объектов.

tailgunner ★★★★★
()
Ответ на: комментарий от paret

Насколько я понимаю, трейты(они же поведения) это замена наследования?

Это немного разные вещи (в Rust наследования типов нет). Трейты больше похожи на интерфейсы из мейнстримных OOP языков (C++, C#, Java и пр.). Более точное соответствие — классы типов из Haskell.

Можно думать о трейтах как о множестве типов, для которых определены некоторые операции.

То есть имеется некий интерфейс(трейт), который в принципе каждый может реализовать по-разному?

Да.

И еще один вопрос: трейты это и есть типажи?

Я это слово в контексте программирования и Rust в частности вообще первый раз слышу, тут нужно quantum-troll спрашивать.

theNamelessOne ★★★★★
()
Последнее исправление: theNamelessOne (всего исправлений: 1)
Ответ на: комментарий от theNamelessOne

Спасибо за разъяснение. Теперь гораздо понятнее с этими определениями. Мне кажется из-за ООП мозги как то заржавели. Не сказать что у меня есть большой опыт программирования, но все же за время учебы термины ООП конкретно так засели в мозгах и тяжко от них избавляться. По мне, так не нужно программы подстраивать по концепцию объектов, ибо программа это в первую очередь алгоритм. На ООП языках вместо того, чтобы продумывать алгоритм, приходится продумывать объекты/классы и отношения между ними. Куда приятнее продумывать структуру типа(объекта) и трейты(поведения), определяющие работу с данным типом. Прошу сильно не ругаться. Это мое видение, как новичка.

paret
() автор топика
Ответ на: комментарий от tailgunner

Я примерно это имел в виду:) Получается, что разработчик должен четко в голове представлять схему времен жизней объектов в программе?

paret
() автор топика
Ответ на: комментарий от paret

Получается, что разработчик должен четко в голове представлять схему времен жизней объектов в программе?

В модуле, который он пишет. Но да, должен. Как же иначе?

tailgunner ★★★★★
()
Ответ на: комментарий от paret

Получается, что разработчик должен четко в голове представлять схему времен жизней объектов в программе?

Именно так. Если, конечно, хочешь писать код, а не бороться с компилятором.

quantum-troll ★★★★★
()
Ответ на: комментарий от quantum-troll

Спасибо за ответы:) Теперь знаю кого доставать вопросами;)

paret
() автор топика
Ответ на: комментарий от ovk48

Как тогда выражать разницу между self, &self и &mut self?

между ) и {, очевидно же

MyTrooName ★★★★★
()
Ответ на: комментарий от paret

Куда приятнее продумывать структуру типа(объекта) и трейты(поведения), определяющие работу с данным типом

Ну вообще-то это и есть ООП. Просто растовая элитота решила, что наследование ненужно/неважно. Но вроде как одумались, так что сидим ждём когда впилят.

foror ★★★★★
()
Ответ на: комментарий от foror

Но вроде как одумались, так что сидим ждём когда впилят.

Скорее всего, когда впилят, то оно всё равно будет не совсем похоже на «классическое наследование». Да и «наследование интерфейсов» уже есть.

DarkEld3r ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.