Что означает строка * массива в Ruby?

Я просматривал исходный код Rails и наткнулся на

# File vendor/rails/activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb, line 129
129:     def target!
130:       @target * ''
131:     end

Что делает * ''? Это умножение на пустую строку...? И почему бы вам это сделать.

Ответы

Ответ 1

Это странный синтаксис. Они эквивалентны:

>> [1, 2, 3] * 'joiner'
=> "1joiner2joiner3"

>> [1, 2, 3].join 'joiner'
=> "1joiner2joiner3"

поэтому в этом случае он объединяет все записи @target в одну строку, между элементами ничего нет.

Примечание: если вы делаете что-то вроде [1, 2, 3] * 3 (используя int вместо str), вы получите вместо него три конкатенированные копии массива.

Ответ 2

Он делает то же самое, что:

["foo","bar","baz"].join

http://ruby-doc.org/core/classes/Array.html#M002210

Per Z.E.D. вы можете использовать его, если хотите запутать людей и сделать свой код более подверженным ошибкам.

Ответ 3

Действительно критический код.

После проверки исходного кода я понял, что @target на самом деле является экземпляром Array, я знаю, что вы можете делать такие вещи как

[5] * 5 # => [5,5,5,5,5]

Я не знаю, где Array#* определено (возможно, в ActiveSupport), но я могу сказать вам, что это поведение, когда оно умножается на String

[1,2,3] * 'comma' # => "1comma2comma3"
[1,2,3] * '' # => '123'

Поэтому я могу заключить, что он объединяет все элементы массива без каких-либо разделителей.

Ответ 4

Array#* с аргументом String эквивалентен Array#join.

Ответ 5

Два комментария:

  • Имея! end имя метода подразумевает, что оно является мутационной операцией, которая, как представляется, не является.

  • Как утверждают другие, это действительно загадочно. Я бы пошел на @target.to_s или @target.join

Ответ 6

Единственная причина, по которой я хочу увидеть, что кто-то хочет использовать * для соединения с массивом строк, - это если они хотят избежать слова join, которое также используется в потоках.

Со следующим:

strings = ["John", "Smith"]
threads = [Thread.new{puts "hai"}, Thread.new{ puts "world!"}]
strings.join(" ") # Legit
threads.each {|thread| thread.join} # Legit

вы можете сделать ошибку при выполнении

threads.join # Not legit, but won't raise an error

Если вы заменили strings.join на strings.*, то в вашем коде будет меньше join. Теперь вы можете сделать grep для них и проверить, что каждый из них выполняется с потоком, а не с массивом. Фактически, вы можете сделать Array#join исключение.