'<<' як звичайний метод
У більшості випадків '<<' - це метод, визначений як і інші, у вашому випадку це означає "додати до кінця цього масиву" (див. Також тут ).
Це у вашому конкретному випадку, але є також багато інших випадків, коли ви зустрінете метод "<<". Я не буду називати його `` оператором '', оскільки це насправді метод, який визначений для якогось об'єкта, який ви можете замінити або реалізувати для власних об'єктів. Інші випадки "<<"
- Конкатенація рядків: "a" << "b"
- Запис виводу в IO: io << "Рядок тексту \ n"
- Запис даних у дайджест повідомлення, HMAC або шифр: sha << "Текст для хешування"
- зсув вліво OpenSSL :: BN: bn << 2
- ...
Визначення класу синглтон
Потім відбувається загадковий зсув поточного обсягу (= зміна самості) у межах потоку програм:
class A
class << self
puts self
end
end
a = A.new
class << a
puts self
end
Таємниця class << self
змусила мене здивуватися та дослідити внутрішні органи. Тоді як у всіх згаданих прикладах <<
насправді є метод, визначений у класі, тобто
obj << stuff
еквівалентно
obj.<<(stuff)
class << self
(Або будь-який об'єкт замість себе) конструкції дійсно відрізняється. Це справді вбудована особливість самої мови, у CRuby це визначено в parse.y як
k_class tLSHFT expr
де tLSHFT - маркер '<<', k_class - ключове слово 'class', а expr - довільний вираз. Тобто ви можете насправді писати
class << <any expression>
і отримає `` переміщення '' в клас синглтона результату виразу. Послідовність tLSHFT буде проаналізовано як вираз 'NODE_SCLASS', який називається визначенням класу Singleton (пор. 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_
Щоб розрізнити "тут оператор документа", довільний роздільник рядка повинен негайно слідувати за "<<". Все, що знаходиться між початковим роздільником та другим випадком цього самого роздільника, буде частиною кінцевого рядка. Також можна використовувати '<< -', різниця полягає в тому, що використання останнього буде ігнорувати будь-який пробіл, що провідний або кінцевий.