Объясните кусок кода Smalltalk? - PullRequest
6 голосов
/ 30 января 2011

Я не могу понять этот кусок кода Smalltalk:

[(line := self upTo: Character cr) size = 0] whileTrue.

Кто-нибудь может помочь объяснить это?

Ответы [ 4 ]

12 голосов
/ 30 января 2011

Одна простая вещь, которую нужно сделать, если у вас есть изображение, из которого пришел код, - запустить на нем отладчик и выполнить шаг.

Если вы столкнулись с кодом вне контекста, как список рассылкипосле этого вы можете просмотреть исполнители одного из сообщений и посмотреть, что оно делает.Например, #size и # whileTrue довольно стандартны, поэтому мы пока пропустим их, но #upTo: звучит интересно.Это напоминает мне о потоковых методах, и появление на них разработчиков подтверждает, что (в Pharo 1.1.1) ReadStream определяет его.Нет комментариев к методу, но OmniBrowser показывает небольшую стрелку рядом с именем метода, указывающую, что он определен в суперклассе.Если мы проверим непосредственный суперкласс, PositionableStream, есть хороший комментарий метода, объясняющий, что делает метод, который рисует из потока до достижения объекта, указанного в аргументе.

Теперь, если мы анализируем код логически, кажется, что это:

  • читает строку из потока (т.е. до кр)
    • , если она пуста (размер = 0), цикл продолжается
    • если это не так, возвращается

Итак, код пропускает все пустые строки и возвращает первую непустую строку.Для подтверждения мы могли бы передать поток в многострочную строку и запустить ее так:

line := nil.
paragraph := '


this is a line of text.
this is another line
line number three' readStream.
[(line := paragraph upTo: Character cr) size = 0] whileTrue.
line. "Returns 'this is a line of text.'"
1 голос
/ 13 ноября 2015

Приоритетными правилами Smalltalk являются
первое: одинарные сообщения
второе: двоичные сообщения
третье: ключевые сообщения
последний: слева направо

Этот порядок слева направо можно изменить с помощью скобок, то есть () скобок. Выражение в паре скобок вычисляется первым. Там, где скобки вложены, сначала оценивается самая внутренняя скобка, а затем направляется наружу к внешней скобке, и, наконец, остатки выражения за скобками.

Из-за сильной тенденции слева направо я часто нахожу полезным читать выражение справа налево.

Так что для [(line := self upTo: Character cr) size = 0] whileTrue.

Подход к нему от конца к началу дает нам следующую интерпретацию.

. Конец выражения. Эквивалент ; в C или Java

whileTrue Что находится слева от него? ] закрытие блочного объекта.

То есть whileTrue - это унарное сообщение, отправляемое в блок [ ... ] то есть продолжайте делать этот блок, пока блок оценивается как true

Блок возвращает результат последнего выражения, оцененного в блоке.

Последнее выражение в блоке - size = 0 сравнение. И двоичное сообщение.

size - это, как правило, одинарное сообщение, отправленное получателю. Итак, мы проверяем size чего-либо, чтобы увидеть, является ли оно 0. Если что-то имеет size из 0, продолжайте.

Что мы проверяем size? Выражение непосредственно слева от имени сообщения. Слева от size есть
(line := self upTo: Character cr)

Это то, что мы хотим знать размером.

Итак, пора положить это выражение под нож.

(line := self upTo: Character cr) является назначением. line будет иметь результат
self upTo: Character cr присвоено ему.

Что находится в правом конце этого выражения? cr Это унарное сообщение, поэтому имеет наивысший приоритет. На что оно отправлено. то есть, что является получателем для сообщения cr?

Сразу слева от него находится Character. Поэтому отправьте классу персонажа сообщение cr. Это оценивает экземпляр класса Character со значением 13, то есть символ возврата каретки.

Так что теперь мы до self upTo: aCarriageReturn

Если self - объект, получающий сообщение self upTo: aCarriageReturn, - не понимает имя сообщения sizeUpto:, это вызовет исключение.

Так что, если это код из работающей системы, мы можем сделать вывод, что self должен быть объектом, который понимает sizeUpTo: В этот момент у меня часто возникает искание искать имя массажа, чтобы увидеть, какие классы имеют сообщение с именем sizeUpto: в их списке имен сообщений, которые они знают и понимают (т.е. их сообщение протокол ).

(В данном случае это мне не помогло - это не метод ни в одном из классов в моей системе Smalltalk).

Но self, похоже, просят разобраться со строкой символов, которая содержит (потенциально) много многократных возвратов каретки.

Итак, верните первую часть aCharacterString до первого возврата каретки.

Если длина aCharacterString от начала до первого возврата каретки равна нулю, продолжайте и сделайте все это снова.

Так что, похоже, мы имеем дело с конкатенацией нескольких строк, оканчивающихся на cr, и обрабатываем каждую по очереди, пока не найдем непустую (кроме возврата каретки), и присваиваем ей line

1 голос
/ 09 июня 2012

Является ли это более читабельным:

while(!strlen(line=gets(self)))

Приведенное выше выражение имеет ошибку, если feof или любую другую ошибку, строка == NULL
Так же имеет выражение Smalltalk, если встречается конец потока, upTo: ответит на пустую коллекцию, и у вас будет бесконечный цикл, если только у вас нет специального потока, который вызывает ошибку в конце потока ...

0 голосов
/ 23 ноября 2011

Одна вещь о Smalltalk, которой я лично не большой поклонник, состоит в том, что, хотя передача сообщений используется последовательно, чтобы делать почти все, иногда может быть трудно определить, какое сообщение отправляется какому получателю.Это связано с тем, что Smalltalk не имеет разделителей для отправки сообщений (таких как Objective-C, например) и вместо этого позволяет вам связывать сообщения в цепочках, следуя набору правил приоритета, которые выглядят примерно так: сообщения отправляются как слева направо.и, если они не разделены круглыми скобками, сначала обрабатываются сообщения со многими ключевыми словами, затем двоичные сообщения с ключевыми словами, затем унарные, а затем без ключевых слов. "Конечно, использование временных переменных или даже круглых скобок, чтобы сделать порядок сообщений явным, может уменьшить количество ситуаций, когда вам нужно подумать об этом порядке операций.Вот пример вышеприведенного кода, разбитого на несколько строк, с использованием временных переменных и скобок для явного упорядочения сообщений для удобства чтения.Я думаю, что это немного яснее о предназначении кода:

line = (self upTo: (Character cr)).

([((line size) = 0)] whileTrue).

Таким образом, в основном, строка - это строка, созданная, когда вы объединяете символы в строке self до символа возврата каретки (Символ cr).Затем мы проверяем размер строки в символах и проверяем, равно ли оно 0, и поскольку мы помещаем это в блок (скобки), мы можем отправить ему whileTrue, которое переоценивает условие в блоке, пока не вернет true.Так что да, хотя True действительно будет более понятным, если бы он назывался doWhileTrue или что-то в этом роде.

Надеюсь, это поможет.

...