#ruby
#ruby
Вопрос:
На днях я ввел в свой код ошибку, показанную ниже, и хотел лучше понять последствия.
File.open('test.txt').readlines do |line|
puts "#{line} test"
end
File.open.readlines работает точно так, как ожидалось, и возвращает массив, содержащий все строки в файле. Но сразу после этого массива находится блок. Например, массив, возвращаемый readlines, не вызывает методов-членов each
. Я предполагаю, что блок ничего не вызывает, поэтому он ничего не делает. На других языках это могло вызвать предупреждение компилятора или в C блок будет считаться вложенной областью и будет выполняться. Но, как показано, Ruby (1.9.2) успешно работает без ошибок и не генерирует никаких выходных puts
данных.
Для полноты картины приведем исправленную версию.
File.open('test.txt').each_line do |line|
puts "#{line} test"
end
Я хотел бы понять поведение первого примера. Верно ли мое предположение о том, что блок по существу анонимный и не выполнялся, потому что его ничто не вызывало?
Комментарии:
1. Что мне кажется странным, так это то, что если я попытаюсь
['a','b','c'] {|s| puts "#{s} test"}
, то получу сообщение об ошибке.readlines
также возвращает массив, но он выполняется без ошибок.2. Да! Я обнаружил то же самое. Это одна из причин, по которой я опубликовал этот вопрос.
Ответ №1:
Вот что происходит в вашем конкретном примере. Когда вы вызываете
File.open('test.txt').readlines do |line|
puts "#{line} test"
end
Блок передается методу readlines. Блок не передается в массив, который возвращается методом readlines . Это допустимый случай, и, следовательно, интерпретатор ruby не жалуется.
Вот более простой сценарий, иллюстрирующий это
Допустим, у меня был класс, определенный следующим образом
class Foo
def bar
end
end
Теперь, если я позвоню
Foo.new.bar {puts "hello"}
Интерпретатор не выдаст никакой ошибки, и сообщение «привет» не будет напечатано.
Если я уступлю блоку в bar следующим образом
class Foo
def bar
yield
end
end
Затем будут выполнены puts, и вы должны увидеть напечатанный hello
Foo.new.bar {puts "hello"} # prints hello
В итоге блоки передаются методам, а не объектам, и вы можете передать блок любому методу в ruby, даже тому, который этого не ожидает.
Комментарии:
1. В этом есть смысл. Очень хороший ответ. Спасибо, потому что мне тоже было интересно.
2. Ах, это тонкость, которую я не учел. Спасибо.