Официальный 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 реализованы как непосредственные (immediate) значения. В случае непосредственных значений переменные хранят сами объекты, а не ссылки на них.
Для таких объектов нельзя определить синглтон-методы. Два объекта Fixnum с одинаковым значением всегда представляют один и тот же экземпляр объекта, поэтому (например) переменные экземпляра для Fixnum со значением 1 разделяются между всеми 1 в системе. Это делает невозможным определение синглтон-метода только для одного из них.
В чем разница между nil и false?
Сначала о сходстве: nil и false — единственные два объекта, которые в булевом контексте вычисляются как false. (Другими словами: это единственные «ложные» значения, все остальные объекты являются «истинными»).
Однако 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 } # альтернативный синтаксис
Символы также можно использовать в качестве перечисляемых значений или для присвоения уникальных значений константам:
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, так как же мне реализовать циклы, проверяющие условие в конце?
О: Clemens Hintze говорит: Вы можете использовать сочетание 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" # парсится как: foo = (nil || "Hello")
foo # => "Hello"
# но, возможно, это удивительно:
foo = nil or "Hello" # парсится как: (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).