В сообщении об ошибке указано «TypeError (без неявного преобразования строки в целочисленное значение)» и что исключение возникло в строке hand[i] == "J"
.Первый элемент, переданный в блок с помощью each
и назначенный переменной блока i
, равен i = hand.first #=> "2"
.Поэтому у нас есть hand["2"] == "J"
, или фактически hand.[]("2")
, но метод Array # [] требует, чтобы его аргумент был целым числом, и «неявного преобразования строки в целое число не существует».
Позвольте мне теперь обратиться к другому аспекту вашего вопроса.
arr = ["2","3","4","5","6","7","8","9","10","J","Q","K","A"]
Вы можете написать следующее.
arr.reduce(0) do |tot, s|
tot +
case s
when "J" then 1
when "Q" then 2
when "K" then 3
when "A" then 4
else 0
end
end
#=> 10
Я вас слышу.Вы говорите: «Я сказал, что хочу использовать .each
!».Ну, у вас есть!Позвольте мне объяснить.
arr
является экземпляром класса Array
.Array
имеет Module # include d the module Enumerable , поэтому мы можем вызвать метод экземпляра Enumerable # redu * on arr
.(Array.included_modules #=> [Enumerable, Kernel]
).
Как и все другие методы экземпляра в Enumerable
, Enumerable # reduce (он же inject
) требует приемника, который является экземпляром класса Перечислитель , но arr
является экземпляром Array
, а не Enumerator
.Руби обходит это следующим образом.Когда reduce
вызывается на arr
, она видит, что arr
не является экземпляром Enumerator
, поэтому она проверяет, есть ли у arr
метод each
(то есть, arr
класс Array
имеет метод экземпляра each
).Это так, поэтому она вызывает each
на arr
для получения
enum = arr.each
#=> #<Enumerator: ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J",
# "Q", "K", "A"]:each>
Теперь у нас есть счетчик, для которого можно вызвать reduce
:
enum.reduce(0) do |tot, s|
tot +
case s
when "J" then 1
when "Q" then 2
when "K" then 3
when "A" then 4
else 0
end
end
#=> 10
Вы неArray#each
не вызывается, но это, безусловно, так.Мы можем подтвердить это, включив Enumerable
в класс, у которого нет метода each
, и посмотрим, что произойдет.
class C
include Enumerable
end
c = C.new
#=> #<C:0x0000000002a118a8>
c.reduce {}
#=> NoMethodError (undefined method `each' for #<C:0x0000000002a118a8>)
class C
def each
end
end
c.reduce {}
#=> nil
Именно поэтому каждый класс, включающий Enumerable
, должен иметь метод экземпляра.each
, который возвращает перечислитель и почему each
вызывается для экземпляров этого класса перед вызовом метода экземпляра из Enumerable
.