Ответ 1
'< <' как обычный метод
В большинстве случаев '< < это метод, определенный как остальные, в вашем случае это означает "добавить к концу этого массива" (см. также здесь).
Это в вашем конкретном случае, но есть также много других случаев, когда вы столкнетесь с "< lt; метод. Я не буду называть это" оператором", поскольку это действительно метод, который определен на каком-либо объекте, который может быть переопределен вами или реализован для ваших собственных объектов. Другие случаи '< lt;
- Конкатенация строк: "a" < "Б"
- Запись вывода в IO: io < "Строка текста \n"
- Запись данных в дайджест сообщений, HMAC или шифр: sha < "Текст будет хэширован"
- смещение влево OpenSSL:: BN: bn < < 2
- ...
Определение класса Singleton
Тогда в потоке программы есть таинственный сдвиг текущего объема (= изменение self):
class A
class << self
puts self # self is the singleton class of A
end
end
a = A.new
class << a
puts self # now it the singleton class of object a
end
Тайна class << self
заставила меня задуматься и исследовать там внутренности. Если во всех примерах, упомянутых выше, <<
- это действительно метод, определенный в классе, т.е.
obj << stuff
эквивалентно
obj.<<(stuff)
Конструкция class << self
(или любой объект вместо self) действительно отличается. Это действительно встроенная особенность самого языка, в CRuby, который он определил в parse.y как
k_class tLSHFT expr
где tLSHFT представляет собой '< token, k_class - это ключевое слово 'class', а expr - произвольное выражение. То есть вы можете написать
class << <any expression>
и будет "смещаться" в одноэлементный класс результата выражения. Последовательность tLSHFT будет анализироваться как выражение 'NODE_SCLASS', которое называется определением класса Singleton (cf. node.c)
case NODE_SCLASS:
ANN("singleton class definition");
ANN("format: class << [nd_recv]; [nd_body]; end");
ANN("example: class << obj; ..; end");
F_NODE(nd_recv, "receiver");
LAST_NODE;
F_NODE(nd_body, "singleton class definition");
break;
Здесь Документы
И как я мог забыть те, здесь Документы используют '< < таким образом, который снова совершенно другой. Вы можете легко определить строку, которая охватывает несколько строк, объявив
here_doc = <<_EOS_
The quick brown fox jumps over the lazy dog.
...
_EOS_
Чтобы отличить оператор "here doc", произвольный ограничитель строк должен немедленно следовать за "< lt;". Все, что находится между этим начальным разделителем и вторым вхождением этого же разделителя, будет частью окончательной строки. Также возможно использовать '< < -', разница заключается в том, что использование последнего будет игнорировать любые ведущие или конечные пробелы.