Що означає << в Ruby?


81

У мене є код:

  def make_all_thumbs(source)
    sizes = ['1000','1100','1200','800','600']
    threads = []
    sizes.each do |s|
      threads << Thread.new(s) {
        create_thumbnail(source+'.png', source+'-'+s+'.png', s)
      }
    end
  end

що <<означає

Відповіді:


143

'<<' як звичайний метод

У більшості випадків '<<' - це метод, визначений як і інші, у вашому випадку це означає "додати до кінця цього масиву" (див. Також тут ).

Це у вашому конкретному випадку, але є також багато інших випадків, коли ви зустрінете метод "<<". Я не буду називати його `` оператором '', оскільки це насправді метод, який визначений для якогось об'єкта, який ви можете замінити або реалізувати для власних об'єктів. Інші випадки "<<"

  • Конкатенація рядків: "a" << "b"
  • Запис виводу в IO: io << "Рядок тексту \ n"
  • Запис даних у дайджест повідомлення, HMAC або шифр: sha << "Текст для хешування"
  • зсув вліво OpenSSL :: BN: bn << 2
  • ...

Визначення класу синглтон

Потім відбувається загадковий зсув поточного обсягу (= зміна самості) у межах потоку програм:

class A
  class << self
    puts self # self is the singleton class of A
  end
end

a = A.new
class << a
  puts self # now it's the singleton class of object a
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_

Щоб розрізнити "тут оператор документа", довільний роздільник рядка повинен негайно слідувати за "<<". Все, що знаходиться між початковим роздільником та другим випадком цього самого роздільника, буде частиною кінцевого рядка. Також можна використовувати '<< -', різниця полягає в тому, що використання останнього буде ігнорувати будь-який пробіл, що провідний або кінцевий.


4
Дуже ґрунтовна відповідь. Це може заплутати початківців, але, як сказав мудра людина ("можливо"), "задайте широке питання, отримайте ґрунтовну відповідь".
Келвін,

1
Привіт, дякую @emboss: так << це еквівалент виклику методу push на масиві?
BKSpurgeon

30

В основному використовується в масивах для додавання значення до кінця масиву.

a = ["orange"]
a << "apple"
puts a

дає це

  ["апельсин", "яблуко"] 
результат.


3
Ще одне використання - <<це в класі успадкування
Забба

7

Це оператор, який дозволяє подавати існуючі масиви, додаючи нові елементи.

У наведеному вище прикладі ви просто заповнюєте порожній масив threads5 новими потоками.



6

У рубінах у вас завжди є один єдиний спосіб зробити щось. Отже, у Ruby є кілька приємних ярликів для загальних імен методів. як цей для .push, замість того, щоб вводити ім'я методу .push, ви можете просто використовувати <<, оператор конкатенації. насправді в деяких випадках ви можете використовувати будь-який із них для однієї і тієї ж операції .push та + із <<.

Як ви можете бачити на цьому прикладі:

alphabet = ["a", "b", "c"]
alphabet << "d" # Update me!
alphabet.push("e") # Update me!
print alphabet 
caption = "the boy is surrounded by "
caption << "weezards!" # Me, too!
caption += " and more. " # Me, too!
# .push can no be uses for concatenate 
print caption

отже, ви бачите результат:

["a", "b", "c", "d", "e"]
the boy is surrounded by weezards! and more.

Ви можете використовувати оператор << для введення елемента в масив або для об'єднання рядка в інший.

отже, що це робить, це створення нового типу елемент / об’єкт Thread і введення його в масив.

 threads << Thread.new(s) {
        create_thumbnail(source+'.png', source+'-'+s+'.png', s)
      }

5

У рубіні оператор << << в основному використовується для:

  1. Додавання значення в масив (в останню позицію)

    [2, 4, 6] << 8 Дасть [2, 4, 6, 8]

  2. Він також використовується для деяких активних операцій із записом в рубіні. Наприклад, у нас є модель Cart і LineItem, пов'язані як cart has_many line_items. Cart.find (A) .line_items поверне об'єкт ActiveRecord :: Associations з позиціями, що належать кошику 'A'.

Тепер, щоб додати (або сказати, щоб пов’язати) ще один елемент_ рядка (X) до кошика (A),

Cart.find(A).line_items << LineItem.find(X)
  1. Тепер додамо інший LineItem до того ж кошика 'A', але цього разу ми не збираємося створювати будь-який об'єкт line_item (я маю на увазі не створюватимуть об'єкт activerecord вручну)

    Cart.find (A) .line_items << LineItem.new

У наведеному вище коді << збереже об'єкт і додасть його до лівого активного масиву асоціації записів.

І багато інших, про які вже йдеться у вищезазначених відповідях.


Не всі знають таку поведінку <<. Дякуємо, що згадали.
Аммар Шах


0

Крім того, починаючи з Ruby 2.6, <<метод також визначений на Proc.

Proc # << дозволяє скласти два або більше процесів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.