Self в Ruby

Честно сказать, достали меня уже вопросом о том, что такое self...

Posted by Марк Мельник on September 8, 2012

Честно сказать, достали меня уже вопросом о том, что такое self. Особено странно, что некоторые люди начинают работать с Ruby on Rails не разобравшись с самим языком Ruby. Ну как так можно? А?! Если лень читать книгу на 600 страниц — есть статьи на RubyDev, они не полностью корректные так как я писал их достаточно давно, но в общем достаточно годные, как мне кажется. Если нет желания прочитать краткие статьи, которые я пытался написать более чем понятным новичку языком, то, я думаю, что программирование — это не ваше. Ну да ладно. Напишу отдельную статью о self, хотя то, что такое self много где упоминалось в статьях на RubyDev.

self — это ссылка на текущий объект.

У каждого метода должен быть приемник — на то он и метод, а не функция, а если приемник не указан, то подразумевается, что приемником является self.

class A
  def hello_and_bye
    hello
    self.bye
  end

  def hello
    puts "Hello!"
  end

  def bye
    puts "Bye!"
  end
end

A.new.hello_and_bye
# Hello!
# Bye!

Разницы нет, использовали мы self или нет, но оба метода #hello и #bye были успешно выполнены.

А вот где есть разница:

class B
  def id_and_class
    puts "id: #{object_id} | class: #{self.class}"
  end
end

B.new.id_and_class
# id: 73604460 | class: B

У объектов имеется метод #class, который возвращает клас, экземпляром которого является объект, однако, существует также зарезервированное слово class, которое используется для объявления класса и вот, чтобы не было многозначности, class — это всегда объявление класса, а потому метод #class всегда следует вызывать указывая объект — приемник явно, то есть: self.class.

self — ссылка на экземпляр класса в методах экземпляра класса, так же как переменные объекта являются переменными экземпляра класса только будучи объявлены в методах экземпляра класса. В контексте тела класса (методов класса и вне их) self является ссылкой на сам класс.

class C
  def self.self
    self
  end
end

C.self #=> C

Этот страшный код, на самом деле объявляет метод .self для объекта self (класса С), который просто возвращает self (класс С). Таким образом Класс C через метод .self возвращает сам себя. Чудно, да?

self используется в трех случаях:

* Для определения методов класса

# так:
class C
  def self.self
    self
  end
end

# или так:
class C
  class << self
    def self
      self
    end
  end
end

* Когда нам нужно явно указать приемник для вызова метода

class D
  def hello
    puts "Hello!"
    bye = "Bye!"
    puts bye
  end

  def bye
    "Trololo"
  end
end

D.new.hello
# Hello!
# Bye!

class E
  def hello
    puts "Hello!"
    bye = "Bye!"
    puts self.bye
  end

  def bye
    "Trololo!"
  end
end

E.new.hello
# Hello!
# Trololo!

* Когда в качестве значения в метод или блок кода объект должен передать сам себя

def puts_id_of_obj(obj)
  puts "Id of object is: #{obj.object_id}"
end

class F
  def puts_my_id
    puts_id_of_obj self
  end
end

F.new.puts_my_id
# Id of object is: 74423470

Может есть еще какие-то экзотические случаи, но на ум ничего не пришло. Если знаете — пишите в комментариях.

Не начинайте работать с Rails, не поняв работы с Ruby. Понимание self — это самые азы, как же можно работать с Rails не зная метапрограммирования, которым пропитан фреймворк насквозь? А я уверен, что вы не знаете метапрограммирования, потому, что это сильно более сложная тема, чем self. this в JavaScript несколько сложнее self, и я уверен, что не понимая self в Ruby вы не понимаете и this в JavaScript, и наоборот. Вы не знаете ни Ruby, ни Javascript, а пытаетесь использовать один из самых современных и full-featured веб-фреймворков?! А атомную станцию не зная элементарной физики вы сможе построить? А маленькие дети могут ходить по канату не умея даже стоять?