Я багато разів бачив у рубінових кодах неперевершені File.open
дзвінки
Можете навести приклад? Я коли-небудь бачив, що в коді, написаному новачками, яким бракує "загальновідомих у більшості мов програмування, процесів роботи з файлами є відкрите використання-закриття".
Досвідчені рубісти або явно закривають свої файли, або, що більш ідіоматично, використовують блокову форму File.open
, яка автоматично закриває файл для вас. Його реалізація в основному виглядає приблизно так:
def File.open(*args, &block)
return open_with_block(*args, &block) if block_given?
open_without_block(*args)
end
def File.open_without_block(*args)
# do whatever ...
end
def File.open_with_block(*args)
yield f = open_without_block(*args)
ensure
f.close
end
Сценарії - це особливий випадок. Зазвичай сценарії виконуються настільки коротко і використовують так мало дескрипторів файлів, що просто немає сенсу їх закривати, оскільки операційна система все одно закриє їх, коли сценарій вийде.
Чи потрібно нам явно закривати?
Так.
Якщо так, то чому GC автоматично закривається?
Оскільки після того, як він зібрав об’єкт, ви більше не можете закрити файл, і, отже, ви отримаєте дескриптори файлів.
Зверніть увагу, що не збирач сміття закриває файли. Збирач сміття просто виконує будь-які фіналізатори для об’єкта, перш ніж він його збирає. Так трапляється, що File
клас визначає фіналізатор, який закриває файл.
Якщо ні, то чому варіант?
Оскільки марно витрачена пам’ять дешева, але марно витрачені дескриптори файлів - ні. Тому не має сенсу прив’язувати час життя дескриптора файлу до часу життя деякої частини пам'яті.
Ви просто не можете передбачити, коли працюватиме збирач сміття. Ви не можете навіть передбачити , якщо він буде працювати на всіх : якщо ви ніколи не закінчаться пам'яті, збирач сміття ніколи не буде працювати, тому фіналізації ніколи не буде працювати, тому файл ніколи не буде закритий.