Выбрать главу

При присваивании переменных ссылки на объекты обобществляются.

y = "abc"

x = y

x # "abc"

После выполнения присваивания x = y и x, и y ссылаются на один и тот же объект:

x.object_id # 53732208

y.object_id # 53732208

Если объект изменяемый, то модификация, примененная к одной переменной, отражается и на другой:

x.gsub!(/а/, "x")

y # "хbс"

Однако новое присваивание любой из этих переменных не влияет на другую:

# Продолжение предыдущего примера

x = "abc"

y # по-прежнему равно "хbс"

Изменяемый объект можно сделать неизменяемым, вызвав метод freeze:

x.freeze

x.gsub!(/b/,"y") # Ошибка!

Символ в Ruby ссылается на переменную по имени, а не по ссылке. Во многих случаях он может вообще не ссылаться на идентификатор, а вести себя как некая разновидность неизменяемой строки. Символ можно преобразовать в строку с помощью метода to_s.

Hearts = :Hearts # Это один из способов присвоить

Clubs = :Clubs # уникальное значение константе,

Diamonds = :Diamonds # некий аналог перечисления

Spades = :Spades # в языках Pascal или С.

puts Hearts.to_s # Печатается "Hearts"

Продемонстрированный выше фокус с «перечислением» был более осмыслен на ранних этапах развития Ruby, когда еще не было класса Symbol, а наличие двоеточия перед идентификатором превращало его в целое число. Если вы пользуетесь таким трюком, не предполагайте, что фактическое значение символа будет неизменным или предсказуемым - просто используйте его как константу, значение которой неважно.

1.3.3. Модули и классы-примеси

Многие встроенные методы наследуются от классов-предков. Особо стоит отметить методы модуля Kernel, подмешиваемые к суперклассу Object. Поскольку класс Object повсеместно доступен, то и добавленные в него из Kernel методы также доступны в любой точке программы. Эти методы играют важную роль в Ruby.

Термины «модуль» и «примесь» — почти синонимы. Модуль представляет собой набор методов и констант, внешних по отношению к программе на Ruby. Его можно использовать просто для управления пространством имен, но основное применение модулей связано с «подмешиванием» его возможностей в класс (с помощью директивы include). В таком случае он используется как класс-примесь.

Этот термин очевидно заимствован из языка Python. Стоит отметить, что в некоторых вариантах LISP такой механизм существует уже больше двадцати лет.

Не путайте описанное выше употребление термина «модуль» с другим значением, которое часто придается ему в информатике. Модуль в Ruby — это не внешний исходный текст и не двоичный файл (хотя может храниться и в том, и в другом виде). Это объектно-ориентированная абстракция, в чем-то похожая на класс.

Примером использования модуля для управления пространством имен служит модуль Math. Так, чтобы получить определение числа π, необязательно включать модуль Math с помощью предложения include; достаточно просто написать Math::PI.

Примесь дает способ получить преимущества множественного наследования, не отягощенные характерными для него проблемами. Можно считать, что это ограниченная форма множественного наследования, но создатель языка Мац называет его одиночным наследованием с разделением реализации.

Отметим, что предложение include включает имена из указанного пространства имен (модуля) в текущее. Метод extend добавляет объекту функции из модуля. В случае применения include методы модуля становятся доступны как методы экземпляра, а в случае extend — как методы класса.

Необходимо оговориться, что операции load и require не имеют ничего общего с модулями: они относятся к исходным и двоичным файлам (загружаемым динамически или статически). Операция load читает файл и вставляет его в текущую точку исходного текста, так что начиная с этой точки становятся видимы все определения, находящиеся во внешнем файле. Операция require аналогична load, но не загружает файл, если он уже был загружен ранее.

Программисты, только начинающие осваивать Ruby, особенно имеющие опыт работы с языком С, могут поначалу путать операции require и include, которые никак не связаны между собой. Вы еще поймаете себя на том, что сначала вызываете require, а потом include для того, чтобы воспользоваться каким-то внешним модулем.

1.3.4. Создание классов

В Ruby есть множество встроенных классов, и вы сами можете определять новые. Для определения нового класса применяется такая конструкция:

class ClassName

# ...

end

Само имя класса - это глобальная константа, поэтому оно должно начинаться с прописной буквы. Определение класса может содержать константы, переменные класса, методы класса, переменные экземпляра и методы экземпляра. Данные уровня класса доступны всем объектам этого класса, тогда как данные уровня экземпляра доступны только одному объекту