Офіційний FAQ Ruby
If you wish to report errors or suggest improvements for this FAQ, please go to our GitHub repository and open an issue or pull request.
Синтаксис
У чому різниця між безпосереднім значенням і посиланням?
This section or parts of it might be out-dated or in need of confirmation.
Fixnum, true, nil і false реалізовані як безпосередні значення.
Для безпосередніх значень змінні зберігають самі об’єкти, а не
посилання на них.
Для таких об’єктів не можна визначати singleton-методи. Два Fixnum
з однаковим значенням завжди представляють той самий екземпляр об’єкта,
тому (наприклад) змінні екземпляра для Fixnum зі значенням 1
спільні для всіх 1 у системі. Це робить неможливим визначення
singleton-методу лише для одного з них.
У чому різниця між nil і false?
Спочатку про схожість: nil і false — єдині два об’єкти,
які в булевому контексті оцінюються як false.
(Інакше кажучи: це єдині «falsy»-значення, усі інші
об’єкти — «truthy».)
Однак nil і false — це екземпляри різних класів
(NilClass і FalseClass) і в інших місцях поводяться по-різному.
Ми рекомендуємо, щоб предикатні методи (ті, чия назва закінчується знаком
питання) повертали true або false. Інші методи, яким потрібно
позначити невдачу, мають повертати nil.
Чому порожній рядок не є false?
П: Порожній рядок ("") повертає true в умовному виразі!
У Perl це false.
В: Але Ruby — не Perl ;-). Все дуже просто: у Ruby лише nil
і false є хибними в умовних контекстах.
Можна використати empty?, порівняти рядок із "" або порівняти його
size чи length із 0, щоб дізнатися, чи рядок порожній.
Що означає :name?
Двокрапка перед іменем створює об’єкт Symbol, який однозначно відповідає
ідентифікатору. Протягом виконання програми для певного імені або рядка
буде створено той самий об’єкт Symbol. Символи також можна створити
за допомогою "name".intern або "name".to_sym.
Об’єкти Symbol можуть представляти ідентифікатори методів, змінних тощо.
Деякі методи, такі як define_method, method_missing або trace_var,
потребують символ. Інші методи, наприклад attr_accessor, send
або autoload, також приймають рядок.
Оскільки вони створюються лише один раз, символи часто використовують як ключі хешів. Рядкові ключі хешів створювали б новий об’єкт для кожного використання, спричиняючи певні витрати пам’яті. Є навіть спеціальний синтаксис для ключів-символів:
person_1 = { :name => "John", :age => 42 }
person_2 = { name: "Jane", age: 24 } # alternate syntax
Символи також можна використовувати як значення переліків або для присвоєння унікальних значень константам:
status = :open # :closed, ...
NORTH = :NORTH
SOUTH = :SOUTH
Як отримати значення символу?
Щоб отримати значення змінної, що відповідає символу, можна використати
symbol.to_s або "#{symbol}", щоб отримати ім’я змінної, а потім
виконати це через eval у відповідній області видимості й отримати
вміст змінної:
a = "This is the content of `a'"
b = eval("#{:a}")
a.object_id == b.object_id # => true
Також можна використати
b = binding.local_variable_get(:a)
Якщо ваш символ відповідає імені методу, можна використати send:
class Demo
def hello
"Hello, world"
end
end
demo = Demo.new
demo.send(:hello)
Або можна використати Object#method, щоб повернути відповідний об’єкт
Method, який потім можна викликати:
m = demo.method(:hello) # => #<Method: Demo#hello>
m.call # => "Hello, world"
Чи є loop керувальною структурою?
Хоча loop виглядає як керувальна структура, насправді це метод,
визначений у Kernel. Блок, що йде за ним, створює нову область
видимості для локальних змінних.
У Ruby немає циклу з перевіркою в кінці
П: У Ruby немає конструкції do { ... } while, тож як реалізувати
цикли, що перевіряють умову наприкінці?
Клеменс Гінце каже: можна використати поєднання begin ... end
та модифікаторів while або until, щоб досягти того самого ефекту:
i = 0
begin
puts "i = #{i}"
i += 1
end until i > 4
Виведе:
i = 0
i = 1
i = 2
i = 3
i = 4
Чому не можна передати літерал хеша до методу: p {}?
{} розбирається як блок, а не як конструктор Hash. Можна змусити
{} трактуватися як вираз, явно вказавши, що це параметр: p({}).
Не можу змусити def pos=(val) працювати!
У мене є такий код, але я не можу використовувати метод pos = 1.
def pos=(val)
@pos = val
puts @pos
end
Методи з = наприкінці потрібно викликати з явним отримувачем
(без отримувача ви просто присвоюєте значення локальній змінній).
Викликайте його як self.pos = 1.
У чому різниця між '\1' і '\\1'?
Вони мають те саме значення. У рядку в одинарних лапках перетворюються
лише \' і \\, інші комбінації залишаються незмінними.
Проте в рядку в подвійних лапках "\1" — це байт \001
(вісімковий бітовий шаблон), тоді як "\\1" — це рядок із двох символів:
зворотний слеш і символ "1".
У чому різниця між .. і ...?
.. включає праву межу діапазону, ... — ні:
(5..8).to_a # => [5, 6, 7, 8]
(5...8).to_a # => [5, 6, 7]
У чому різниця між or і ||?
П: p(nil || "Hello") друкує "Hello", тоді як p(nil or "Hello")
дає синтаксичну помилку. Чому?
В: or має дуже низький пріоритет, p( (nil or "Hello") ) спрацює.
Пріоритет or, наприклад, також нижчий, ніж у =,
тоді як || має вищий пріоритет:
foo = nil || "Hello" # parsed as: foo = (nil || "Hello")
foo # => "Hello"
# but perhaps surprisingly:
foo = nil or "Hello" # parsed as: (foo = nil) or "Hello"
foo # => nil
or (і так само and) найкраще використовувати не для поєднання
булевих виразів, а для керування потоком виконання, наприклад
do_something or raise "some error!"
де do_something повертає false або nil, коли стається помилка.
Чи є в Ruby вказівники на функції?
Об’єкт Proc, створений Proc.new, proc або lambda, можна зберегти
в змінній, тож така змінна може вважатися вказівником на функцію. Також
можна отримати посилання на методи конкретного екземпляра об’єкта
за допомогою object.method.
У чому різниця між load і require?
load завантажує і виконує програму Ruby (*.rb).
require також завантажує програми Ruby, але ще й бінарні модулі
розширень Ruby (спільні бібліотеки або DLL). Крім того, require
гарантує, що один і той самий компонент не буде завантажено більше
одного разу.
Чи є в Ruby обробка винятків?
Ruby підтримує гнучку схему обробки винятків:
begin
statements which may raise exceptions
rescue [exception class names]
statements when an exception occurred
rescue [exception class names]
statements when an exception occurred
ensure
statements that will always run
end
Якщо в блоці begin виникає виняток, виконується rescue із
відповідною назвою винятку. Блок ensure виконується незалежно від того,
чи стався виняток. Частини rescue та ensure можна опустити.
Якщо для rescue не вказано клас винятку, мається на увазі
StandardError, і перехоплюються винятки, що перебувають у відношенні
is_a? до StandardError.
Цей вираз повертає значення блоку begin.
Останній виняток доступний через глобальну змінну $!
(і тому його тип можна визначити за допомогою $!.type).