Небольшое исправление: вы не вызываете блок, вы вызываете метод.
Единственные блоки в представленном вами коде - это аргументы whileTrue: и являются частными для метода (недоступны изснаружи).
Это заблуждение не ваша вина.Это связано с блочной нотацией, используемой этим форматом файла для разграничения методов.Лично мне это не нравится, я нахожу это более запутанным, чем полезным (за исключением того, что я выгляжу как более распространенные языки, дань языкам на основе файлов).
Итак, как вы вызываете метод?Вы делаете это, отправляя сообщение, другого пути нет.Все, что вы можете сделать, это отправить сообщение.Smalltalk ориентирован на сообщения.Это сообщения до самого конца.
При получении сообщения объект будет искать селектор сообщений в своем словаре методов класса.Если нет, это будет поиск в суперклассе и т. Д. Но это дело самого объекта.
Итак, в конце концов, вы на самом деле не думаете о вызове метода, потому что другой объект может ответитьк тому же сообщению другим методом.Вы должны думать с точки зрения делегирования задачи специализированному объекту, то есть с точки зрения сообщения и связанного с ней контракта.
Так, каковы контракты?Вы хотите, чтобы на карте был костюм (Club, Spade, ...) и ранг (от 1 до 13).Итак, вы создали класс Card с этими двумя переменными экземплярами.Пока все хорошо.
Затем вы хотите создать свои 52 карты, чтобы заполнить колоду.Это экземпляр класса Card.Как ты это делаешь?Вы отправили сообщение new
в класс Card.Вы можете создать более подходящее сообщение класса, которое будет выступать в качестве конструктора Карты, с учетом масти и ранга.
Это будет что-то вроде
Card class >> newWithSuit: aSuit rank: anInteger
[<category: 'instance creation'>
^self basicNew setSuit: aSuit rank: anInteger ]
setSuit: aSuit rank: anInteger
[<category: 'private'>
suit := aSuit.
rank := anInteger ]
Тогда вам не нужноОпределите отдельные сеттеры (getSuit:
и setRank:
в вашем коде), потому что вы, вероятно, не хотите изменять эти атрибуты впоследствии, кроме как во время создания.Вот почему я обычно предпочитаю один сеттер, который я классифицирую как «частный».Это всего лишь соглашение, но именно так мы определяем контракты в Smalltalk с помощью набора неформальных соглашений, а также с помощью методов и комментариев к классам (и SUnit TestCase, особенно если вы используете тестовый дизайн).
Youрешили закодировать ранг в целое число от 1 до 13. Это нормально.Но вы также должны решить, как представлять костюм.Это неясно в вашем коде, потому что есть смесь целочисленных (от 1 до 4) и необъявленных переменных (Club, Spade, ...).Это глобальные переменные?
Тогда вам не нужно кодировать эти масти и ранжировать в массиве размера 2, это абсолютно не нужно, поскольку все эти данные уже содержатся в объектах Card.Таким образом, вы должны заполнить колоду:
content at: deckRank put: (Card newWithSuit: suitNumber rank: rankNumber).
Запомните скобки: вы отправляете сообщение at:put:
на content
с двумя параметрами, deckRank
и значение, возвращаемое другим сообщением, отправляет (Card newWithSuit: suitNumber rank: rankNumber)
Мы ожидаем, что это будет правильно инициализированный экземпляр Card.
В коде, который вы предоставили Card at: 1 put: Card setRank: b
, вы отправляете сообщение at:put:setRank:
в класс Card
с 3 параметрами, целочисленный литерал 1,класс Card
и объект, указанный переменной b
.Это, вероятно, не ваше намерение.Там также есть строка |
, следующая за b
, которая не совсем похожа на правильный синтаксис.Полоски предназначены для разграничения временных переменных или отделения аргументов блока от инструкций блока внутри блока или могут также представлять собой двоичное сообщение, но в этом случае требуется аргумент (каждое двоичное сообщение, например + - * /, имеет получателя и аргумент).
Надеюсь, я дал вам несколько полезных советов, но, возможно, вам придется прочитать и применить некоторые пошаговые руководства по Smalltalk, чтобы лучше ознакомиться с этими основными понятиями.