Smalltalk в примерах/Специальные переменные, буквы и символы
Смолток очень маленький язык, с очень большой библиотекой классов. Но, несмотря на то, что он маленький, есть вещи которые надо изучать.
Пары символов
правитьЕсть несколько пар символов, которые имеют особое значение, когда они используются вместе. Браузер VisualWorks делает простым манипулирование с текстом и парами символов. Вы можете заключить блок текста в пару символов, выделив его и затем нажав \emph{Esc-leftCharacter} (---). Вы можете выделить весь текст между парой символов, дважды щёлкнув между символом и текстом. Вы можете убрать пару символов, выделив текст между парой и затем нажав \emph{Esc-leftCharacter}.
Это комментарий
правитьТекст между двойными кавычками - это текст комментария, и он не компилируется. Ты можешь пометить блок текста как комментарий выделив его и затем нажав \emph{Esc-"}.
'Это строка'
правитьЗаключение последовательности букв в одинарные кавычки - это способ создать экземпляр Строки. Смотри ниже раздел "Автоматически создаваемые объекты".
(2*3)
правитьЗаключение выражения в круглые скобки даёт ему наивысший приоритет. То есть, \verb|1+(2 * 3)| означает что \verb|2 * 3| будет вычислено до прибавления результата к \verb|1|. Круглые скобки также используются для заключения литеральных массивов (см. далее).
[некоторый код]
правитьОкружение кода квадратными скобками создаёт экземпляр BlockClosure. Смотри ниже раздел "Автоматически создаваемые объекты".
Приставки
править$ Знак доллара - это приставка для создания экземпляра класса Буква. Смотри ниже раздел "Автоматически создаваемые объекты".
\# \potom
Специальные переменные
правитьСпециальная переменная \emph{сам} - это получатель сообщения, или объект выполняющий метод. Ты используешь \emph{сам} когда объект хочет послать сообщение себе. Это описано более полно в Главе 2, Сообщения.
Специальная переменная \emph{супер} ссылается на суперкласс класса, в котором \emph{определён} текущий выполняемый метод. Это описано более полно в Главе 2, Сообщения.
\potom
Transcript cr; show: thisContext printString.
Присваивание
править- = используется для присваивания значения переменной. Например,
число := 3.
Присвоение выполняется последним в предложении (исключая возвращаемое значение). Таким образом, следующая строка присваивает строку '68' переменной x.
x := 67.8 округлить минус строкаДляПечати копироватьОт: 2 до: 3.
Оператор присвоения обычно называется 'становится' или 'двоеточие равно' при разговоре. При использовании для присваивания специального названия отличного от 'равно' даёт меньшую вероятность того что ты напечатаешь так: \verb|число = 3|, что означает посылку сообщения числу с аргументом 3, и возвращение значения типа Логический.
Заметьте, что Вы можете использовать множественное присваивание, хотя я не рекомендую использовать его, так как оно не очень ясное. Например,
x := y := 3.
Возвращаемое значение
правитьСимвол шляпки (\^{}) - это символ возвращаемого значения. Если выполняющейся строкой является \verb|^3|, выполнение метода закончится и он возвратит МалоеЦелое со значением 3. \^{} выполняется в самую последнюю очередь в предложении. В следующем примере переменная \emph{instVar} получит значение $-3$, затем значение instVar (то есть $-3$) будет возвращено из метода.
^instVar := 3.14 усечь минус.
По умолчанию метод возвращает \emph{сам}. То есть, если выполнение метода доходит до конца без явного выполнения (\^{}), он возвращает \emph{сам}. \potom. \potom.
Иногда ты можешь увидеть довольно сложно выглядящее возвращаемое значение. В следующих примерах приведены два наиболее часто встречающихся случая использования (\^{}). В первом примере, ты можешь думать о возвращении из блока или \potom. Во втором примере, мы возвращаем результат построения новой совокупности за одну операцию вместо помещения новой совокупности во временную переменную и затем возвращения этой переменной.
^объектОдин > объектДва истина?: [объектОдин] лож?: [объектДва]
^некотораяСовокупность собрать: [ :каждый | сам manipulate: каждый]
Разделитель предложений
правитьТочка (.) - это разделитель предложений. Если есть два предложения, первое предложение нуждается в точке чтобы дать компилятору понять что первое предложение закончилось и второе начинается. Пропуск точки это одна из самых распространённых ошибок и обычно она вызывает исключение сообщениеНеПонятно когда Смолток рассматривает первое слово во втором предложении как сообщение которое посылается результату выполнения первого предложения. Лучшим способом проверить нет ли пропущенных точек запустить форматировщик после написания метода. Если метод выглядит не так как ты ожидаешь, ты возможно пропустил точку.
Заметь что точка - это \emph{не} ограничитель предложений. Метод с одним предложением не нуждается в точке. Не нужна точка и для последнего предложения в методе или блоке. Это отличается от C++, где точка с запятой - это ограничитель, и она нужна для всех выражений. Однако точка, поставленная после предложения, где она не нужна - это не ошибка. Я обычно не забочусь о лишних точках. После того, как я заканчиваю писать метод, и метод компилируется (то есть он успешно принимается), я запускаю форматировщик, который удаляет все ненужные скобки и точки.
Каскадирование
правитьОператор каскадирования - это точка с запятой (;). Каскадирование позволяет посылать различные сообщения одному и тому же объекту, когда добавляется много элементов в совокупность, изменяя различные его поля. Например,
Transcript cr; показать: 'это строка'.
аСовокупность добавить: 'этот'; добавить: 'тот'.
печататьНа: аПоток аПоток печать: сам класс; crtab; печать: сам перЭкзОдин.
Если ты используешь каскадирование, обычно принятой практикой является помещение сообщений в одну строку, затем каждый каскад помещается на отдельной строке, \potom. Короткие сообщения, такие как cr, или tab, обычно помещаются на той же строке. К сожалению, форматировщик разрушает отступы определённые тобой для каскада. Из-за этого, я часто указываю получателя каждый раз и использую точку для разделения предложений. При этом нет потери производительности.
Автоматически создаваемые объекты
правитьЕсть некоторые объекты которые создаются автоматически вместо явного послания сообщения \verb|новый| классу.
Малые целые
править4 --- экземпляр класса МалоеЦэлое может быть создан просто при использовании целого значения. Одной из интересных особенностей целых --- ты не можешь получить переполнения целого если ты добавишь единицу к самому большому МаломуЦэлому, возвращаемое значение метода + это БольшоеПоложытельноеЦэлое. Попробуй выполнить
МалоеЦэлое максимальноеЗначение + 1.
Числа с плавающей точкой
править3.14 --- экземпляр класса ПлавающаяТочка может быть создан при использовании значения с плавающей точкой.
Строки
править\verb|'это строка'| --- экземпляр Строки (на самом деле подкласса Строки) может быть создан при заключении последовательности букв в одинарные кавычки. Строка это забавный класс потому что даже если ты напишешь \verb|Строка новый| ты по прежнему получишь экземпляр подкласса Строки. Для создания строки содержащей одинарную кавычку, используй две одинарные кавычки для определения кавычки в строке. Например,
'You cant do that'
Буквы
править\$А --- экземпляр Буквы может быть создан при помощи предшествующего знака доллара и буквы. Например, буква Х создаётся при написании \$Х. Ты можешь создать экземпляр пробела, табуляции, --- и другие невидимые символы таким же способом; например, ты можешь создать пробел как \$\ и перевод строки набрав \$ и нажав ввод. Однако, такой способ труден для чтения, поэтому предпочтительный способ создания таких букв --- послать соответствующее сообщение Букве (например, \verb|Буква пробел| или \verb|Буква cr|). Чтобы узнать какие буквы могут быть созданы при помощи посылки сообщений, смотри сообщения стороны класса Буквы или выполни \verb|Буква именаКонстант|.
Символы
править\#notFound --- экземпляр Символа может быть создан при помощи приставки \# и последовательности букв. Если тебе нужен символ содержащий пробелы, ты можешь заключить имя символа в одинарные кавычки. Например, \#'not found'. Если ты inspect этот символ, он будет показываться вместе с кавычками, но когда ты посмотришь первый символ, ты увидишь что это \$n вместо одинарной кавычки.
Массивы
править\#(1.1 \$а 'hi') --- экземпляр Массива может быть создан путём помещения других автоматически создаваемых объектов между скобками с предшествующим символом \#. Заметь пробелы между элементами массива. Заметь так же что элементы массива не обязаны быть одного типа.
Ты не можешь использовать эту конструкцию для объектов нуждающихся в сообщении для создания. То есть ты \emph{не} можешь сказать \#(1 (Буква cr)) и ожидать, что ты получишь массив из целого числа и буквы. Однако, ты \emph{можешь} создать литеральный массив который содержит другие литеральные массивы, такой как \#(1 \#(1.1 'hi' \#(2 \#symbol)))
Блоки
править['привет' эхо] --- экземпляр BlockClosure может быть создан путём помещения кода между квадратными скобками. Код не будет выполнен до тех пор, пока он не получит сообщение из группы \verb|значение|. Ты можешь поместить код в блок и затем передать его другому методу где он будет выполнен. Блоки часто помещаются в Dictionaries для последующего обращения и выполнения. Заметь, что значение блока это значение последнего предложения, выполненного в блоке. То есть значение \verb|[3. 4. 5. 1]| --- 1.
У блока могут быть параметры, которые определяются при помощи двоеточия перед именем параметра и отделяются вертикальной чертой от оставшегося кода. Например [ :параметр | параметр эхо ]. В блоках также могут быть временные переменные, которые помещаются между вертикальными чертами. Например, [ :параметр || временно | временно := параметр * 2. временно эхо].
---
---
[ :parameter | parameter echo ] clean [ :parameter | | temp | temp := parameter ] clean [ :parameter | self foo: parameter ] copying (note the self) [ methodTemporary echo ] copying or full [ :parameter | A parameter * 3 ] full
= и ==
правитьДва сообщения = и == не специальные как символы описанные выше; они просто бинарные сообщения подобные другим бинарным сообщениям. Однако, есть несколько замечаний, которые заслуживают нашего внимания, и лучше упомянуть о них в этом месте.
Сообщение = возвращает \emph{истину} если два объекта равны, в то время как сообщение == возвращает \emph{истина} если два объекта \emph{идентичны}. Что это означает? (Сообщения противоположные = и == --- \~{} и \~{}\~{}.)
Идентичность
правитьДва объекты \emph{идентичны} когда они \emph{точно} один и тот же объект. Смолток узнаёт, что объекты идентичны, если они имеют один и тот же указатель на объект. Указатель на объект это 32 битная величина, некоторые биты несут информацию о том где находится значение или значение объекта. Если у тебя есть объект сотрудник, указатель на объект будут отражать объект сотрудник который существует где-нибудь в памяти. Два объект сотрудник идентичны, если указатели на объект ссылаются на одно и то же место в памяти.
С другой стороны, некоторые объекты могут быть представлены полностью 32 битами. Такие объекты возвращают \emph{истину} когда им посылается сообщение \verb|прямой?|, и сейчас это объекты классов \emph{МалоеЦэлое} и \emph{Буква}. (Максимальное значение МаловаЦэлова меньше, чем максимальное значение 32 битного целого, потому что три бита используется для определения того, что МалоеЦэлое а не указатель на объект.) Из-за способа хранения, одинаково названные экземпляры Символа тоже идентичны.
3 == 3 истина $а == $а истина #абв == #абв истина истина == истина истина nil == nil истина 'абв' == 'абв' ложь 3.14 == 3.14 ложь #(1 $а) == #(1 $а) ложь
Если ты рассмотришь следующий пример, ты найдёшь что x идентичен y. Это происходит из-за того что присваивание не копирует значение; оно связывает объект с новой переменной то есть обе переменные содержат один и тот же объект.
x := #(1 $a). y := x. x == y истина
\subsection{Равенство}
Объекты \emph{равны}, когда их переменные содержат одинаковые значения. Две строки с одинаковыми буквами будут равны. Если мы посмотрим на примеры выше, которые возвращают ложь, и проверим эти объекты на равенство, мы получим
'абв' == 'абв' ложь 3.14 == 3.14 ложь #(1 $а) == #(1 $а) ложь
Если ты определишь новый класс как метод сравнения по умолчанию, то как это работает, когда два объекта сравниваются? Ответ ---. Если ты посмотришь, как определён метод сравнения по умолчанию в классе Объект, ты увидишь, что он использует сравнение на идентичность. То есть = просто работает как \verb|^сам == аОбъект|.
Если ты определишь свой собственный метод сравнения ты должен написать метод \verb|hash| и наоборот. Два одинаковых объекта должны иметь одинаковое хеш-значение. Причина, по которой \verb|hash| и = ходят рука об руку --- некоторые совокупности помещают объекты используя хеширование (такие как Словарь, Множество и Мешок).
---.
MyClass>>= anObject class == self class ifFalse: [ ^ false ].
MyClass>>= (anObject isKindOf: self class) ifFalse: [ ^ false ].